From f6a79955f8625bbcb520f49dec684642d82cfb2d Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Mon, 24 Jul 2023 11:24:45 +0200 Subject: [PATCH 01/28] Initial commit. --- README | 1 + 1 file changed, 1 insertion(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 000000000..a0990367e --- /dev/null +++ b/README @@ -0,0 +1 @@ +TBD From 808f96b8f788d18cff864e5fe1863ed16b522fff Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Fri, 25 Aug 2023 14:42:45 +0100 Subject: [PATCH 02/28] KXI-28991 initial commit --- ChatGPT_Retrieval_Plugin_QA.ipynb | 459 ++ ..._Retrieval_Plugin_QA.ipynb:Zone.Identifier | 3 + Dockerfile | 24 + LICENSE | 21 + Makefile | 14 + README.md | 607 +++ datastore/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 153 bytes .../__pycache__/datastore.cpython-310.pyc | Bin 0 -> 3346 bytes datastore/__pycache__/factory.cpython-310.pyc | Bin 0 -> 2183 bytes datastore/datastore.py | 86 + datastore/factory.py | 72 + datastore/providers/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 163 bytes .../kdbai_datastore.cpython-310.pyc | Bin 0 -> 7184 bytes .../kdbai_datastore.cpython-311.pyc | Bin 0 -> 10860 bytes .../pinecone_datastore.cpython-310.pyc | Bin 0 -> 6756 bytes datastore/providers/analyticdb_datastore.py | 312 ++ datastore/providers/azuresearch_datastore.py | 260 + datastore/providers/chroma_datastore.py | 250 + .../providers/elasticsearch_datastore.py | 351 ++ datastore/providers/kdbai_datastore.py | 421 ++ datastore/providers/llama_datastore.py | 181 + datastore/providers/milvus_datastore.py | 560 +++ datastore/providers/pgvector_datastore.py | 181 + datastore/providers/pinecone_datastore.py | 262 + datastore/providers/postgres_datastore.py | 132 + datastore/providers/qdrant_datastore.py | 297 ++ datastore/providers/redis_datastore.py | 391 ++ datastore/providers/supabase_datastore.py | 95 + datastore/providers/weaviate_datastore.py | 385 ++ datastore/providers/zilliz_datastore.py | 65 + docs/deployment/flyio.md | 89 + docs/deployment/heroku.md | 105 + docs/deployment/other-options.md | 17 + .../removing-unused-dependencies.md | 20 + docs/deployment/render-thumbnail.png | Bin 0 -> 260172 bytes docs/deployment/render.md | 19 + docs/providers/analyticdb/setup.md | 82 + docs/providers/azuresearch/setup.md | 29 + docs/providers/chroma/setup.md | 29 + docs/providers/elasticsearch/setup.md | 37 + docs/providers/llama/setup.md | 51 + docs/providers/milvus/setup.md | 43 + docs/providers/pinecone/setup.md | 35 + docs/providers/postgres/setup.md | 81 + docs/providers/qdrant/setup.md | 58 + docs/providers/redis/setup.md | 37 + docs/providers/supabase/setup.md | 87 + docs/providers/weaviate/setup.md | 79 + docs/providers/zilliz/setup.md | 46 + .../no-auth/ai-plugin.json | 18 + .../authentication-methods/no-auth/main.py | 144 + .../oauth/ai-plugin.json | 25 + .../service-http/ai-plugin.json | 22 + .../user-http/ai-plugin.json | 19 + examples/docker/elasticsearch/README.md | 7 + .../docker/elasticsearch/docker-compose.yaml | 27 + examples/docker/milvus/docker-compose.yaml | 49 + examples/docker/qdrant/README.md | 46 + examples/docker/qdrant/docker-compose.yaml | 17 + examples/docker/qdrant/documents.json | 23 + examples/docker/qdrant/queries.json | 7 + examples/docker/redis/docker-compose.yml | 18 + examples/memory/README.md | 15 + examples/memory/ai-plugin.json | 19 + examples/memory/main.py | 183 + examples/memory/openapi.yaml | 276 ++ examples/providers/elasticsearch/search.ipynb | 724 +++ .../providers/pinecone/semantic-search.ipynb | 809 ++++ .../redis/semantic-search-and-filter.ipynb | 511 ++ examples/providers/supabase/.gitignore | 3 + examples/providers/supabase/config.toml | 72 + .../20230414142107_init_pg_vector.sql | 70 + examples/providers/supabase/seed.sql | 0 local_server/ai-plugin.json | 18 + local_server/logo.png | Bin 0 -> 17015 bytes local_server/main.py | 148 + local_server/openapi.yaml | 190 + models/__pycache__/api.cpython-310.pyc | Bin 0 -> 1469 bytes models/__pycache__/models.cpython-310.pyc | Bin 0 -> 2845 bytes models/api.py | 34 + models/models.py | 66 + poetry.lock | 4251 +++++++++++++++++ pyproject.toml | 70 + scripts/process_json/README.md | 24 + scripts/process_json/example.json | 25 + scripts/process_json/process_json.py | 147 + scripts/process_jsonl/README.md | 24 + scripts/process_jsonl/example.jsonl | 6 + scripts/process_jsonl/process_jsonl.py | 145 + scripts/process_zip/README.md | 24 + scripts/process_zip/example.zip | Bin 0 -> 53296 bytes scripts/process_zip/process_zip.py | 152 + server/__pycache__/main.cpython-310.pyc | Bin 0 -> 4027 bytes server/main.py | 157 + services/__init__.py | 0 services/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 152 bytes services/__pycache__/chunks.cpython-310.pyc | Bin 0 -> 4338 bytes services/__pycache__/date.cpython-310.pyc | Bin 0 -> 867 bytes services/__pycache__/file.cpython-310.pyc | Bin 0 -> 3153 bytes services/__pycache__/openai.cpython-310.pyc | Bin 0 -> 2132 bytes services/chunks.py | 203 + services/date.py | 24 + services/extract_metadata.py | 43 + services/file.py | 117 + services/openai.py | 77 + services/pii_detection.py | 32 + tests/__init__.py | 0 .../analyticdb/test_analyticdb_datastore.py | 323 ++ .../azuresearch/test_azuresearch_datastore.py | 139 + .../providers/chroma/test_chroma_datastore.py | 293 ++ .../test_elasticsearch_datastore.py | 158 + .../providers/llama/test_llama_datastore.py | 95 + .../providers/milvus/test_milvus_datastore.py | 354 ++ .../postgres/test_postgres_datastore.py | 291 ++ .../providers/qdrant/test_qdrant_datastore.py | 280 ++ .../providers/redis/test_redis_datastore.py | 64 + .../supabase/test_supabase_datastore.py | 291 ++ .../providers/weaviate/docker-compose.yml | 25 + .../weaviate/test_weaviate_datastore.py | 538 +++ .../providers/zilliz/test_zilliz_datastore.py | 29 + 122 files changed, 18334 insertions(+) create mode 100644 ChatGPT_Retrieval_Plugin_QA.ipynb create mode 100644 ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 datastore/__init__.py create mode 100644 datastore/__pycache__/__init__.cpython-310.pyc create mode 100644 datastore/__pycache__/datastore.cpython-310.pyc create mode 100644 datastore/__pycache__/factory.cpython-310.pyc create mode 100644 datastore/datastore.py create mode 100644 datastore/factory.py create mode 100644 datastore/providers/__init__.py create mode 100644 datastore/providers/__pycache__/__init__.cpython-310.pyc create mode 100644 datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc create mode 100644 datastore/providers/__pycache__/kdbai_datastore.cpython-311.pyc create mode 100644 datastore/providers/__pycache__/pinecone_datastore.cpython-310.pyc create mode 100644 datastore/providers/analyticdb_datastore.py create mode 100644 datastore/providers/azuresearch_datastore.py create mode 100644 datastore/providers/chroma_datastore.py create mode 100644 datastore/providers/elasticsearch_datastore.py create mode 100644 datastore/providers/kdbai_datastore.py create mode 100644 datastore/providers/llama_datastore.py create mode 100644 datastore/providers/milvus_datastore.py create mode 100644 datastore/providers/pgvector_datastore.py create mode 100644 datastore/providers/pinecone_datastore.py create mode 100644 datastore/providers/postgres_datastore.py create mode 100644 datastore/providers/qdrant_datastore.py create mode 100644 datastore/providers/redis_datastore.py create mode 100644 datastore/providers/supabase_datastore.py create mode 100644 datastore/providers/weaviate_datastore.py create mode 100644 datastore/providers/zilliz_datastore.py create mode 100644 docs/deployment/flyio.md create mode 100644 docs/deployment/heroku.md create mode 100644 docs/deployment/other-options.md create mode 100644 docs/deployment/removing-unused-dependencies.md create mode 100644 docs/deployment/render-thumbnail.png create mode 100644 docs/deployment/render.md create mode 100644 docs/providers/analyticdb/setup.md create mode 100644 docs/providers/azuresearch/setup.md create mode 100644 docs/providers/chroma/setup.md create mode 100644 docs/providers/elasticsearch/setup.md create mode 100644 docs/providers/llama/setup.md create mode 100644 docs/providers/milvus/setup.md create mode 100644 docs/providers/pinecone/setup.md create mode 100644 docs/providers/postgres/setup.md create mode 100644 docs/providers/qdrant/setup.md create mode 100644 docs/providers/redis/setup.md create mode 100644 docs/providers/supabase/setup.md create mode 100644 docs/providers/weaviate/setup.md create mode 100644 docs/providers/zilliz/setup.md create mode 100644 examples/authentication-methods/no-auth/ai-plugin.json create mode 100644 examples/authentication-methods/no-auth/main.py create mode 100644 examples/authentication-methods/oauth/ai-plugin.json create mode 100644 examples/authentication-methods/service-http/ai-plugin.json create mode 100644 examples/authentication-methods/user-http/ai-plugin.json create mode 100644 examples/docker/elasticsearch/README.md create mode 100644 examples/docker/elasticsearch/docker-compose.yaml create mode 100644 examples/docker/milvus/docker-compose.yaml create mode 100644 examples/docker/qdrant/README.md create mode 100644 examples/docker/qdrant/docker-compose.yaml create mode 100644 examples/docker/qdrant/documents.json create mode 100644 examples/docker/qdrant/queries.json create mode 100644 examples/docker/redis/docker-compose.yml create mode 100644 examples/memory/README.md create mode 100644 examples/memory/ai-plugin.json create mode 100644 examples/memory/main.py create mode 100644 examples/memory/openapi.yaml create mode 100644 examples/providers/elasticsearch/search.ipynb create mode 100644 examples/providers/pinecone/semantic-search.ipynb create mode 100644 examples/providers/redis/semantic-search-and-filter.ipynb create mode 100644 examples/providers/supabase/.gitignore create mode 100644 examples/providers/supabase/config.toml create mode 100644 examples/providers/supabase/migrations/20230414142107_init_pg_vector.sql create mode 100644 examples/providers/supabase/seed.sql create mode 100644 local_server/ai-plugin.json create mode 100644 local_server/logo.png create mode 100644 local_server/main.py create mode 100644 local_server/openapi.yaml create mode 100644 models/__pycache__/api.cpython-310.pyc create mode 100644 models/__pycache__/models.cpython-310.pyc create mode 100644 models/api.py create mode 100644 models/models.py create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 scripts/process_json/README.md create mode 100644 scripts/process_json/example.json create mode 100644 scripts/process_json/process_json.py create mode 100644 scripts/process_jsonl/README.md create mode 100644 scripts/process_jsonl/example.jsonl create mode 100644 scripts/process_jsonl/process_jsonl.py create mode 100644 scripts/process_zip/README.md create mode 100644 scripts/process_zip/example.zip create mode 100644 scripts/process_zip/process_zip.py create mode 100644 server/__pycache__/main.cpython-310.pyc create mode 100644 server/main.py create mode 100644 services/__init__.py create mode 100644 services/__pycache__/__init__.cpython-310.pyc create mode 100644 services/__pycache__/chunks.cpython-310.pyc create mode 100644 services/__pycache__/date.cpython-310.pyc create mode 100644 services/__pycache__/file.cpython-310.pyc create mode 100644 services/__pycache__/openai.cpython-310.pyc create mode 100644 services/chunks.py create mode 100644 services/date.py create mode 100644 services/extract_metadata.py create mode 100644 services/file.py create mode 100644 services/openai.py create mode 100644 services/pii_detection.py create mode 100644 tests/__init__.py create mode 100644 tests/datastore/providers/analyticdb/test_analyticdb_datastore.py create mode 100644 tests/datastore/providers/azuresearch/test_azuresearch_datastore.py create mode 100644 tests/datastore/providers/chroma/test_chroma_datastore.py create mode 100644 tests/datastore/providers/elasticsearch/test_elasticsearch_datastore.py create mode 100644 tests/datastore/providers/llama/test_llama_datastore.py create mode 100644 tests/datastore/providers/milvus/test_milvus_datastore.py create mode 100644 tests/datastore/providers/postgres/test_postgres_datastore.py create mode 100644 tests/datastore/providers/qdrant/test_qdrant_datastore.py create mode 100644 tests/datastore/providers/redis/test_redis_datastore.py create mode 100644 tests/datastore/providers/supabase/test_supabase_datastore.py create mode 100644 tests/datastore/providers/weaviate/docker-compose.yml create mode 100644 tests/datastore/providers/weaviate/test_weaviate_datastore.py create mode 100644 tests/datastore/providers/zilliz/test_zilliz_datastore.py diff --git a/ChatGPT_Retrieval_Plugin_QA.ipynb b/ChatGPT_Retrieval_Plugin_QA.ipynb new file mode 100644 index 000000000..b0de93bc7 --- /dev/null +++ b/ChatGPT_Retrieval_Plugin_QA.ipynb @@ -0,0 +1,459 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# KDBAI for Q&A with ChatGPT Retrieval Plugin" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Install Python 3.10 if not already installed.\n", + "\n", + "2. Clone the `retrieval-app` repository:\n", + "\n", + "```\n", + "git clone git@github.com:openai/retrieval-app.git\n", + "```\n", + "\n", + "3. Navigate to the app directory:\n", + "\n", + "```\n", + "cd /path/to/retrieval-app\n", + "```\n", + "\n", + "4. Install `poetry`:\n", + "\n", + "```\n", + "pip install poetry\n", + "```\n", + "\n", + "5. Create a new virtual environment:\n", + "\n", + "```\n", + "poetry env use python3.10\n", + "```\n", + "\n", + "6. Install the `retrieval-app` dependencies:\n", + "\n", + " Before installing the dependencies with poetry, we will need to add pyKX and a local KDBAI python package as a dependence in the `pyproject.toml` file. This can be done by pointing the KDBAI package under `[tool.poetry.dependencies]` by adding the following lines.\n", + "\n", + " - __pykx = \"^1.6.0\"__\n", + " - __kdbai = { path = \"path/to/kdbaiPackage.tar.gz\", develop = false }__\n", + "\n", + "```\n", + "poetry install\n", + "```\n", + "\n", + "7. Set app environment variables:\n", + "\n", + "* `BEARER_TOKEN`: Secret token used by the app to authorize incoming requests. The token can be generated using [jwt.io](https://jwt.io/).\n", + "\n", + "* `OPENAI_API_KEY`: The OpenAI API key used for generating embeddings with the `text-embedding-ada-002` model. [Get an API key here](https://platform.openai.com/account/api-keys)!\n", + "\n", + "8. Set `KDBAI`-specific environment variables:\n", + "\n", + "* `DATASTORE`: set to `kdbai`.\n", + "\n", + "8. Run the app with:\n", + "\n", + "```\n", + "poetry run start\n", + "```\n", + "When the application is up and running a FastAPI server exposes the ChatGPT plugin's endpoints for `upserting`, `querying`, and `deleting` documents.\n", + "\n", + "During the start up of the application `KDBAI` initiates a new HNSW index named `openaiEmbeddings` with default parameters {\"efConstruction\": 8, \"efSearch\": 8, \"M\": 32}" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/alexg/Applications/miniforge3/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import os\n", + "import requests\n", + "from tqdm.auto import tqdm\n", + "from datasets import load_dataset\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# If the bearer token is not set as an environment variable, you can set it manually here\n", + "BEARER_TOKEN = os.environ.get(\"BEARER_TOKEN\")\n", + "headers = {\"Authorization\": f\"Bearer {BEARER_TOKEN}\"}" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load Dataset from Hugging Face\n", + "\n", + "The Adversarial_QA dataset is chosen for this demo.\n", + "The adversarial human annotation paradigm ensures that these datasets consist of questions that current state-of-the-art models find challenging." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Found cached dataset adversarial_qa (/Users/alexg/.cache/huggingface/datasets/adversarial_qa/adversarialQA/1.0.0/92356be07b087c5c6a543138757828b8d61ca34de8a87807d40bbc0e6c68f04b)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of unique contexts: 2648\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecontextquestionanswersmetadata
07ba1e8f4261d3170fcf42e84a81dd749116fae95BrainAnother approach to brain function is to exami...What sare the benifts of the blood brain barrir?{'text': ['isolated from the bloodstream'], 'a...{'split': 'train', 'model_in_the_loop': 'Combi...
12936a8460bfffe437b54cf3ec1e825a3b7b5627a1BrainMotor systems are areas of the brain that are ...What do you think with?{'text': ['brain'], 'answer_start': [467]}{'split': 'train', 'model_in_the_loop': 'Combi...
24e40737d487964dbcd26a223f2799cf56390a98a8BrainThe brain is an organ that serves as the cente...How are neurons connected?{'text': ['synapses'], 'answer_start': [602]}{'split': 'train', 'model_in_the_loop': 'Combi...
37a0f8e785a10f6e21e24207d24ba2823162383062BrainThe SCN projects to a set of areas in the hypo...The body's central biological clock is contain...{'text': ['SCN'], 'answer_start': [4]}{'split': 'train', 'model_in_the_loop': 'Combi...
536d753d4a8878b5f5bc496d9a369b8c0b212079a0BrainThe brain contains several motor areas that pr...What is at the highest level?{'text': ['the primary motor cortex'], 'answer...{'split': 'train', 'model_in_the_loop': 'Combi...
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 7ba1e8f4261d3170fcf42e84a81dd749116fae95 Brain \n", + "12 936a8460bfffe437b54cf3ec1e825a3b7b5627a1 Brain \n", + "24 e40737d487964dbcd26a223f2799cf56390a98a8 Brain \n", + "37 a0f8e785a10f6e21e24207d24ba2823162383062 Brain \n", + "53 6d753d4a8878b5f5bc496d9a369b8c0b212079a0 Brain \n", + "\n", + " context \\\n", + "0 Another approach to brain function is to exami... \n", + "12 Motor systems are areas of the brain that are ... \n", + "24 The brain is an organ that serves as the cente... \n", + "37 The SCN projects to a set of areas in the hypo... \n", + "53 The brain contains several motor areas that pr... \n", + "\n", + " question \\\n", + "0 What sare the benifts of the blood brain barrir? \n", + "12 What do you think with? \n", + "24 How are neurons connected? \n", + "37 The body's central biological clock is contain... \n", + "53 What is at the highest level? \n", + "\n", + " answers \\\n", + "0 {'text': ['isolated from the bloodstream'], 'a... \n", + "12 {'text': ['brain'], 'answer_start': [467]} \n", + "24 {'text': ['synapses'], 'answer_start': [602]} \n", + "37 {'text': ['SCN'], 'answer_start': [4]} \n", + "53 {'text': ['the primary motor cortex'], 'answer... \n", + "\n", + " metadata \n", + "0 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "12 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "24 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "37 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "53 {'split': 'train', 'model_in_the_loop': 'Combi... " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = load_dataset(\"adversarial_qa\", 'adversarialQA', split=\"train\").to_pandas()\n", + "data = data.drop_duplicates(subset=[\"context\"])\n", + "print(f\"Number of unique contexts: {len(data)}\")\n", + "data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'id': '7ba1e8f4261d3170fcf42e84a81dd749116fae95',\n", + " 'text': 'Another approach to brain function is to examine the consequences of damage to specific brain areas. Even though it is protected by the skull and meninges, surrounded by cerebrospinal fluid, and isolated from the bloodstream by the blood–brain barrier, the delicate nature of the brain makes it vulnerable to numerous diseases and several types of damage. In humans, the effects of strokes and other types of brain damage have been a key source of information about brain function. Because there is no ability to experimentally control the nature of the damage, however, this information is often difficult to interpret. In animal studies, most commonly involving rats, it is possible to use electrodes or locally injected chemicals to produce precise patterns of damage and then examine the consequences for behavior.',\n", + " 'metadata': {'title': 'Brain'}},\n", + " {'id': '936a8460bfffe437b54cf3ec1e825a3b7b5627a1',\n", + " 'text': 'Motor systems are areas of the brain that are directly or indirectly involved in producing body movements, that is, in activating muscles. Except for the muscles that control the eye, which are driven by nuclei in the midbrain, all the voluntary muscles in the body are directly innervated by motor neurons in the spinal cord and hindbrain. Spinal motor neurons are controlled both by neural circuits intrinsic to the spinal cord, and by inputs that descend from the brain. The intrinsic spinal circuits implement many reflex responses, and contain pattern generators for rhythmic movements such as walking or swimming. The descending connections from the brain allow for more sophisticated control.',\n", + " 'metadata': {'title': 'Brain'}},\n", + " {'id': 'e40737d487964dbcd26a223f2799cf56390a98a8',\n", + " 'text': \"The brain is an organ that serves as the center of the nervous system in all vertebrate and most invertebrate animals. Only a few invertebrates such as sponges, jellyfish, adult sea squirts and starfish do not have a brain; diffuse or localised nerve nets are present instead. The brain is located in the head, usually close to the primary sensory organs for such senses as vision, hearing, balance, taste, and smell. The brain is the most complex organ in a vertebrate's body. In a typical human, the cerebral cortex (the largest part) is estimated to contain 15–33 billion neurons, each connected by synapses to several thousand other neurons. These neurons communicate with one another by means of long protoplasmic fibers called axons, which carry trains of signal pulses called action potentials to distant parts of the brain or body targeting specific recipient cells.\",\n", + " 'metadata': {'title': 'Brain'}}]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Formatting the documents for the retrieval plugin requests\n", + "documents = [\n", + " {\n", + " 'id': r['id'],\n", + " 'text': r['context'],\n", + " 'metadata': {\n", + " 'title': r['title']\n", + " }\n", + " } for r in data.to_dict(orient='records')\n", + "]\n", + "documents[:3]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Insert data to the HNSW Index" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 27/27 [00:38<00:00, 1.44s/it]\n" + ] + } + ], + "source": [ + "batchSize = 100\n", + "s = requests.Session()\n", + "\n", + "for i in tqdm(range(0, len(documents), batchSize)):\n", + " i_end = min(len(documents), i+batchSize)\n", + " res = s.post(\n", + " \"http://localhost:8000/upsert\",\n", + " headers=headers,\n", + " json={\n", + " \"documents\": documents[i:i_end]\n", + " }\n", + " )" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Query the HNSW index" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'query': 'Who went into orbit following Gagarin?'}, {'query': 'Who was responsible for being the best in the Soveit space prgram?'}]\n" + ] + } + ], + "source": [ + "# Select questions from the AdversarialQA dataset\n", + "queries = data['question'].tolist()\n", + "\n", + "queries = [{'query': queries[i]} for i in range(len(queries))]\n", + "searchQueries = queries[150:152]\n", + "print(searchQueries)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "results = requests.post(\n", + " \"http://0.0.0.0:8000/query\",\n", + " headers=headers,\n", + " json={\n", + " 'queries': searchQueries\n", + " }\n", + ")\n", + "results" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "----------------------------------------------------------------------\n", + "Who went into orbit following Gagarin?\n", + "\n", + "0.35: On May 1, 1960, a U.S. one-man U-2 spy plane was reportedly shot down at high altitude over Soviet Union airspace. The flight was made to gain photo intelligence before the scheduled opening of an East–West summit conference, which had been scheduled in Paris, 15 days later. Captain Francis Gary Powers had bailed out of his aircraft and was captured after parachuting down onto Russian soil. Four days after Powers disappeared, the Eisenhower Administration had NASA issue a very detailed press release noting that an aircraft had \"gone missing\" north of Turkey. It speculated that the pilot might have fallen unconscious while the autopilot was still engaged, and falsely claimed that \"the pilot reported over the emergency frequency that he was experiencing oxygen difficulties.\n", + "0.46: In 1955 American nuclear arms policy became one aimed primarily at arms control as opposed to disarmament. The failure of negotiations over arms until 1955 was due mainly to the refusal of the Russians to permit any sort of inspections. In talks located in London that year, they expressed a willingness to discuss inspections; the tables were then turned on Eisenhower, when he responded with an unwillingness on the part of the U.S. to permit inspections. In May of that year the Russians agreed to sign a treaty giving independence to Austria, and paved the way for a Geneva summit with the U.S., U.K. and France. At the Geneva Conference Eisenhower presented a proposal called \"Open Skies\" to facilitate disarmament, which included plans for Russia and the U.S. to provide mutual access to each other's skies for open surveillance of military infrastructure. Russian leader Nikita Khrushchev dismissed the proposal out of hand.\n", + "0.5: On 6 August 1940, Estonia was annexed by the Soviet Union as the Estonian SSR. The provisions in the Estonian constitution requiring a popular referendum to decide on joining a supra-national body were ignored. Instead the vote to join the Soviet Union was taken by those elected in the elections held the previous month. Additionally those who had failed to do their \"political duty\" of voting Estonia into the USSR, specifically those who had failed to have their passports stamped for voting, were condemned to death by Soviet tribunals. The repressions followed with the mass deportations carried out by the Soviets in Estonia on 14 June 1941. Many of the country's political and intellectual leaders were killed or deported to remote areas of the USSR by the Soviet authorities in 1940–1941. Repressive actions were also taken against thousands of ordinary people.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n", + "----------------------------------------------------------------------\n", + "Who was responsible for being the best in the Soveit space prgram?\n", + "\n", + "0.46: From 1920, Eisenhower served under a succession of talented generals – Fox Conner, John J. Pershing, Douglas MacArthur and George Marshall. He first became executive officer to General Conner in the Panama Canal Zone, where, joined by Mamie, he served until 1924. Under Conner's tutelage, he studied military history and theory (including Carl von Clausewitz's On War), and later cited Conner's enormous influence on his military thinking, saying in 1962 that \"Fox Conner was the ablest man I ever knew.\" Conner's comment on Eisenhower was, \"[He] is one of the most capable, efficient and loyal officers I have ever met.\" On Conner's recommendation, in 1925–26 he attended the Command and General Staff College at Fort Leavenworth, Kansas, where he graduated first in a class of 245 officers.\n", + "0.47: On May 1, 1960, a U.S. one-man U-2 spy plane was reportedly shot down at high altitude over Soviet Union airspace. The flight was made to gain photo intelligence before the scheduled opening of an East–West summit conference, which had been scheduled in Paris, 15 days later. Captain Francis Gary Powers had bailed out of his aircraft and was captured after parachuting down onto Russian soil. Four days after Powers disappeared, the Eisenhower Administration had NASA issue a very detailed press release noting that an aircraft had \"gone missing\" north of Turkey. It speculated that the pilot might have fallen unconscious while the autopilot was still engaged, and falsely claimed that \"the pilot reported over the emergency frequency that he was experiencing oxygen difficulties.\n", + "0.49: RCA/Jive Label Group CEO Barry Weiss left the company in March 2011 to become the new CEO of Island Def Jam and Universal Republic, which were both part of Universal Music Group. Weiss had been the RCA/Jive Label Group CEO since 2008 and was head of Jive Records since 1991.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n" + ] + } + ], + "source": [ + "for query_response in results.json()['results']:\n", + " query = query_response['query']\n", + " answers = []\n", + " scores = []\n", + " for result in query_response['results']:\n", + " answers.append(result['text'])\n", + " scores.append(round(result['score'], 2))\n", + " # Print the scores and corresponding answers\n", + " print(\"-\"*70+\"\\n\"+query+\"\\n\\n\"+\"\\n\".join([f\"{s}: {a}\" for a, s in zip(answers, scores)])+\"\\n\"+\"-\"*70+\"\\n\\n\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.10" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier b/ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier new file mode 100644 index 000000000..8de5cfaa3 --- /dev/null +++ b/ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +HostUrl=https://files.slack.com/files-pri/T0HLFPUJE-F05J0S9UA8P/download/chatgpt_retrieval_plugin_qa.ipynb?origin_team=T0HLFPUJE diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..dbd5ec9de --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ + +FROM python:3.10 as requirements-stage + +WORKDIR /tmp + +RUN pip install poetry + +COPY ./pyproject.toml ./poetry.lock* /tmp/ + + +RUN poetry export -f requirements.txt --output requirements.txt --without-hashes + +FROM python:3.10 + +WORKDIR /code + +COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +COPY . /code/ + +# Heroku uses PORT, Azure App Services uses WEBSITES_PORT, Fly.io uses 8080 by default +CMD ["sh", "-c", "uvicorn server.main:app --host 0.0.0.0 --port ${PORT:-${WEBSITES_PORT:-8080}}"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..b3841f631 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 OpenAI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..3aaafbf26 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +# Heroku +# make heroku-login +# make heroku-push + +HEROKU_APP = + +heroku-push: + docker buildx build --platform linux/amd64 -t ${HEROKU_APP} . + docker tag ${HEROKU_APP} registry.heroku.com/${HEROKU_APP}/web + docker push registry.heroku.com/${HEROKU_APP}/web + heroku container:release web -a ${HEROKU_APP} + +heroku-login: + heroku container:login diff --git a/README.md b/README.md new file mode 100644 index 000000000..2586bc2f6 --- /dev/null +++ b/README.md @@ -0,0 +1,607 @@ +# ChatGPT Retrieval Plugin + +> **Join the [ChatGPT plugins waitlist here](https://openai.com/waitlist/plugins)!** + +Find an example video of a Retrieval Plugin that has access to the UN Annual Reports from 2018 to 2022 [here](https://cdn.openai.com/chat-plugins/retrieval-gh-repo-readme/Retrieval-Final.mp4). + +## Introduction + +The ChatGPT Retrieval Plugin repository provides a flexible solution for semantic search and retrieval of personal or organizational documents using natural language queries. The repository is organized into several directories: + +| Directory | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| [`datastore`](/datastore) | Contains the core logic for storing and querying document embeddings using various vector database providers. | +| [`docs`](/docs) | Includes documentation for setting up and using each vector database provider, webhooks, and removing unused dependencies. | +| [`examples`](/examples) | Provides example configurations, authentication methods, and provider-specific examples. | +| [`local_server`](/local_server) | Contains an implementation of the retrieval plugin configured for localhost testing. | +| [`models`](/models) | Contains the data models used by the plugin, such as document and metadata models. | +| [`scripts`](/scripts) | Offers scripts for processing and uploading documents from different data sources. | +| [`server`](/server) | Houses the main FastAPI server implementation. | +| [`services`](/services) | Contains utility services for tasks like chunking, metadata extraction, and PII detection. | +| [`tests`](/tests) | Includes integration tests for various vector database providers. | +| [`.well-known`](/.well-known) | Stores the plugin manifest file and OpenAPI schema, which define the plugin configuration and API specification. | + +This README provides detailed information on how to set up, develop, and deploy the ChatGPT Retrieval Plugin. + +## Table of Contents + +- [Quickstart](#quickstart) +- [About](#about) + - [Plugins](#plugins) + - [Retrieval Plugin](#retrieval-plugin) + - [Memory Feature](#memory-feature) + - [Security](#security) + - [API Endpoints](#api-endpoints) +- [Development](#development) + - [Setup](#setup) + - [General Environment Variables](#general-environment-variables) + - [Choosing a Vector Database](#choosing-a-vector-database) + - [Pinecone](#pinecone) + - [Elasticsearch](#elasticsearch) + - [Weaviate](#weaviate) + - [Zilliz](#zilliz) + - [Milvus](#milvus) + - [Qdrant](#qdrant) + - [Redis](#redis) + - [Llama Index](#llamaindex) + - [Chroma](#chroma) + - [Azure Cognitive Search](#azure-cognitive-search) + - [Supabase](#supabase) + - [Postgres](#postgres) + - [AnalyticDB](#analyticdb) + - [Running the API Locally](#running-the-api-locally) + - [Testing a Localhost Plugin in ChatGPT](#testing-a-localhost-plugin-in-chatgpt) + - [Personalization](#personalization) + - [Authentication Methods](#authentication-methods) +- [Deployment](#deployment) +- [Installing a Developer Plugin](#installing-a-developer-plugin) +- [Webhooks](#webhooks) +- [Scripts](#scripts) +- [Limitations](#limitations) +- [Contributors](#contributors) +- [Future Directions](#future-directions) + +## Quickstart + +Follow these steps to quickly set up and run the ChatGPT Retrieval Plugin: + +1. Install Python 3.10, if not already installed. +2. Clone the repository: `git clone https://github.com/openai/chatgpt-retrieval-plugin.git` +3. Navigate to the cloned repository directory: `cd /path/to/chatgpt-retrieval-plugin` +4. Install poetry: `pip install poetry` +5. Create a new virtual environment with Python 3.10: `poetry env use python3.10` +6. Activate the virtual environment: `poetry shell` +7. Install app dependencies: `poetry install` +8. Create a [bearer token](#general-environment-variables) +9. Set the required environment variables: + + ``` + export DATASTORE= + export BEARER_TOKEN= + export OPENAI_API_KEY= + + # Optional environment variables used when running Azure OpenAI + export OPENAI_API_BASE=https://.openai.azure.com/ + export OPENAI_API_TYPE=azure + export OPENAI_EMBEDDINGMODEL_DEPLOYMENTID= + export OPENAI_METADATA_EXTRACTIONMODEL_DEPLOYMENTID= + export OPENAI_COMPLETIONMODEL_DEPLOYMENTID= + export OPENAI_EMBEDDING_BATCH_SIZE= + + # Add the environment variables for your chosen vector DB. + # Some of these are optional; read the provider's setup docs in /docs/providers for more information. + + # Pinecone + export PINECONE_API_KEY= + export PINECONE_ENVIRONMENT= + export PINECONE_INDEX= + + # Weaviate + export WEAVIATE_URL= + export WEAVIATE_API_KEY= + export WEAVIATE_CLASS= + + # Zilliz + export ZILLIZ_COLLECTION= + export ZILLIZ_URI= + export ZILLIZ_USER= + export ZILLIZ_PASSWORD= + + # Milvus + export MILVUS_COLLECTION= + export MILVUS_HOST= + export MILVUS_PORT= + export MILVUS_USER= + export MILVUS_PASSWORD= + + # Qdrant + export QDRANT_URL= + export QDRANT_PORT= + export QDRANT_GRPC_PORT= + export QDRANT_API_KEY= + export QDRANT_COLLECTION= + + # AnalyticDB + export PG_HOST= + export PG_PORT= + export PG_USER= + export PG_PASSWORD= + export PG_DATABASE= + export PG_COLLECTION= + + + # Redis + export REDIS_HOST= + export REDIS_PORT= + export REDIS_PASSWORD= + export REDIS_INDEX_NAME= + export REDIS_DOC_PREFIX= + export REDIS_DISTANCE_METRIC= + export REDIS_INDEX_TYPE= + + # Llama + export LLAMA_INDEX_TYPE= + export LLAMA_INDEX_JSON_PATH= + export LLAMA_QUERY_KWARGS_JSON_PATH= + export LLAMA_RESPONSE_MODE= + + # Chroma + export CHROMA_COLLECTION= + export CHROMA_IN_MEMORY= + export CHROMA_PERSISTENCE_DIR= + export CHROMA_HOST= + export CHROMA_PORT= + + # Azure Cognitive Search + export AZURESEARCH_SERVICE= + export AZURESEARCH_INDEX= + export AZURESEARCH_API_KEY= (optional, uses key-free managed identity if not set) + + # Supabase + export SUPABASE_URL= + export SUPABASE_ANON_KEY= + + # Postgres + export PG_HOST= + export PG_PORT= + export PG_USER= + export PG_PASSWORD= + export PG_DATABASE= + + # Elasticsearch + export ELASTICSEARCH_URL= (either specify host or cloud_id) + export ELASTICSEARCH_CLOUD_ID= + + export ELASTICSEARCH_USERNAME= + export ELASTICSEARCH_PASSWORD= + export ELASTICSEARCH_API_KEY= + + export ELASTICSEARCH_INDEX= + export ELASTICSEARCH_REPLICAS= + export ELASTICSEARCH_SHARDS= + ``` + +10. Run the API locally: `poetry run start` +11. Access the API documentation at `http://0.0.0.0:8000/docs` and test the API endpoints (make sure to add your bearer token). + +### Testing in ChatGPT + +To test a locally hosted plugin in ChatGPT, follow these steps: + +1. Run the API on localhost: `poetry run dev` +2. Follow the instructions in the [Testing a Localhost Plugin in ChatGPT](#testing-a-localhost-plugin-in-chatgpt) section of the README. + +For more detailed information on setting up, developing, and deploying the ChatGPT Retrieval Plugin, refer to the full Development section below. + +## About + +### Plugins + +Plugins are chat extensions designed specifically for language models like ChatGPT, enabling them to access up-to-date information, run computations, or interact with third-party services in response to a user's request. They unlock a wide range of potential use cases and enhance the capabilities of language models. + +Developers can create a plugin by exposing an API through their website and providing a standardized manifest file that describes the API. ChatGPT consumes these files and allows the AI models to make calls to the API defined by the developer. + +A plugin consists of: + +- An API +- An API schema (OpenAPI JSON or YAML format) +- A manifest (JSON file) that defines relevant metadata for the plugin + +The Retrieval Plugin already contains all of these components. Read the Chat Plugins blogpost [here](https://openai.com/blog/chatgpt-plugins), and find the docs [here](https://platform.openai.com/docs/plugins/introduction). + +### Retrieval Plugin + +This is a plugin for ChatGPT that enables semantic search and retrieval of personal or organizational documents. It allows users to obtain the most relevant document snippets from their data sources, such as files, notes, or emails, by asking questions or expressing needs in natural language. Enterprises can make their internal documents available to their employees through ChatGPT using this plugin. + +The plugin uses OpenAI's `text-embedding-ada-002` embeddings model to generate embeddings of document chunks, and then stores and queries them using a vector database on the backend. As an open-source and self-hosted solution, developers can deploy their own Retrieval Plugin and register it with ChatGPT. The Retrieval Plugin supports several vector database providers, allowing developers to choose their preferred one from a list. + +A FastAPI server exposes the plugin's endpoints for upserting, querying, and deleting documents. Users can refine their search results by using metadata filters by source, date, author, or other criteria. The plugin can be hosted on any cloud platform that supports Docker containers, such as Fly.io, Heroku, Render, or Azure Container Apps. To keep the vector database updated with the latest documents, the plugin can process and store documents from various data sources continuously, using incoming webhooks to the upsert and delete endpoints. Tools like [Zapier](https://zapier.com) or [Make](https://www.make.com) can help configure the webhooks based on events or schedules. + +### Memory Feature + +A notable feature of the Retrieval Plugin is its capacity to provide ChatGPT with memory. By utilizing the plugin's upsert endpoint, ChatGPT can save snippets from the conversation to the vector database for later reference (only when prompted to do so by the user). This functionality contributes to a more context-aware chat experience by allowing ChatGPT to remember and retrieve information from previous conversations. Learn how to configure the Retrieval Plugin with memory [here](/examples/memory). + +### Security + +The Retrieval Plugin allows ChatGPT to search a vector database of content, and then add the best results into the ChatGPT session. This means it doesn’t have any external effects, and the main risk consideration is data authorization and privacy. Developers should only add content into their Retrieval Plugin that they have authorization for and that they are fine with appearing in users’ ChatGPT sessions. You can choose from a number of different authentication methods to secure the plugin (more information [here](#authentication-methods)). + +### API Endpoints + +The Retrieval Plugin is built using FastAPI, a web framework for building APIs with Python. FastAPI allows for easy development, validation, and documentation of API endpoints. Find the FastAPI documentation [here](https://fastapi.tiangolo.com/). + +One of the benefits of using FastAPI is the automatic generation of interactive API documentation with Swagger UI. When the API is running locally, Swagger UI at `/docs` can be used to interact with the API endpoints, test their functionality, and view the expected request and response models. + +The plugin exposes the following endpoints for upserting, querying, and deleting documents from the vector database. All requests and responses are in JSON format, and require a valid bearer token as an authorization header. + +- `/upsert`: This endpoint allows uploading one or more documents and storing their text and metadata in the vector database. The documents are split into chunks of around 200 tokens, each with a unique ID. The endpoint expects a list of documents in the request body, each with a `text` field, and optional `id` and `metadata` fields. The `metadata` field can contain the following optional subfields: `source`, `source_id`, `url`, `created_at`, and `author`. The endpoint returns a list of the IDs of the inserted documents (an ID is generated if not initially provided). + +- `/upsert-file`: This endpoint allows uploading a single file (PDF, TXT, DOCX, PPTX, or MD) and storing its text and metadata in the vector database. The file is converted to plain text and split into chunks of around 200 tokens, each with a unique ID. The endpoint returns a list containing the generated id of the inserted file. + +- `/query`: This endpoint allows querying the vector database using one or more natural language queries and optional metadata filters. The endpoint expects a list of queries in the request body, each with a `query` and optional `filter` and `top_k` fields. The `filter` field should contain a subset of the following subfields: `source`, `source_id`, `document_id`, `url`, `created_at`, and `author`. The `top_k` field specifies how many results to return for a given query, and the default value is 3. The endpoint returns a list of objects that each contain a list of the most relevant document chunks for the given query, along with their text, metadata and similarity scores. + +- `/delete`: This endpoint allows deleting one or more documents from the vector database using their IDs, a metadata filter, or a delete_all flag. The endpoint expects at least one of the following parameters in the request body: `ids`, `filter`, or `delete_all`. The `ids` parameter should be a list of document IDs to delete; all document chunks for the document with these IDS will be deleted. The `filter` parameter should contain a subset of the following subfields: `source`, `source_id`, `document_id`, `url`, `created_at`, and `author`. The `delete_all` parameter should be a boolean indicating whether to delete all documents from the vector database. The endpoint returns a boolean indicating whether the deletion was successful. + +The detailed specifications and examples of the request and response models can be found by running the app locally and navigating to http://0.0.0.0:8000/openapi.json, or in the OpenAPI schema [here](/.well-known/openapi.yaml). Note that the OpenAPI schema only contains the `/query` endpoint, because that is the only function that ChatGPT needs to access. This way, ChatGPT can use the plugin only to retrieve relevant documents based on natural language queries or needs. However, if developers want to also give ChatGPT the ability to remember things for later, they can use the `/upsert` endpoint to save snippets from the conversation to the vector database. An example of a manifest and OpenAPI schema that gives ChatGPT access to the `/upsert` endpoint can be found [here](/examples/memory). + +To include custom metadata fields, edit the `DocumentMetadata` and `DocumentMetadataFilter` data models [here](/models/models.py), and update the OpenAPI schema [here](/.well-known/openapi.yaml). You can update this easily by running the app locally, copying the JSON found at http://0.0.0.0:8000/sub/openapi.json, and converting it to YAML format with [Swagger Editor](https://editor.swagger.io/). Alternatively, you can replace the `openapi.yaml` file with an `openapi.json` file. + +## Development + +### Setup + +This app uses Python 3.10, and [poetry](https://python-poetry.org/) for dependency management. + +Install Python 3.10 on your machine if it isn't already installed. It can be downloaded from the official [Python website](https://www.python.org/downloads/) or with a package manager like `brew` or `apt`, depending on your system. + +Clone the repository from GitHub: + +``` +git clone https://github.com/openai/chatgpt-retrieval-plugin.git +``` + +Navigate to the cloned repository directory: + +``` +cd /path/to/chatgpt-retrieval-plugin +``` + +Install poetry: + +``` +pip install poetry +``` + +Create a new virtual environment that uses Python 3.10: + +``` +poetry env use python3.10 +poetry shell +``` + +Install app dependencies using poetry: + +``` +poetry install +``` + +**Note:** If adding dependencies in the `pyproject.toml`, make sure to run `poetry lock` and `poetry install`. + +#### General Environment Variables + +The API requires the following environment variables to work: + +| Name | Required | Description | +| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `DATASTORE` | Yes | This specifies the vector database provider you want to use to store and query embeddings. You can choose from `elasticsearch`, `chroma`, `pinecone`, `weaviate`, `zilliz`, `milvus`, `qdrant`, `redis`, `azuresearch`, `supabase`, `postgres`, `analyticdb`. | +| `BEARER_TOKEN` | Yes | This is a secret token that you need to authenticate your requests to the API. You can generate one using any tool or method you prefer, such as [jwt.io](https://jwt.io/). | +| `OPENAI_API_KEY` | Yes | This is your OpenAI API key that you need to generate embeddings using the `text-embedding-ada-002` model. You can get an API key by creating an account on [OpenAI](https://openai.com/). | + +### Using the plugin with Azure OpenAI + +The Azure Open AI uses URLs that are specific to your resource and references models not by model name but by the deployment id. As a result, you need to set additional environment variables for this case. + +In addition to the `OPENAI_API_BASE` (your specific URL) and `OPENAI_API_TYPE` (azure), you should also set `OPENAI_EMBEDDINGMODEL_DEPLOYMENTID` which specifies the model to use for getting embeddings on upsert and query. For this, we recommend deploying `text-embedding-ada-002` model and using the deployment name here. + +If you wish to use the data preparation scripts, you will also need to set `OPENAI_METADATA_EXTRACTIONMODEL_DEPLOYMENTID`, used for metadata extraction and +`OPENAI_COMPLETIONMODEL_DEPLOYMENTID`, used for PII handling. + +### Choosing a Vector Database + +The plugin supports several vector database providers, each with different features, performance, and pricing. Depending on which one you choose, you will need to use a different Dockerfile and set different environment variables. The following sections provide brief introductions to each vector database provider. + +For more detailed instructions on setting up and using each vector database provider, please refer to the respective documentation in the `/docs/providers//setup.md` file ([folders here](/docs/providers)). + +#### Pinecone + +[Pinecone](https://www.pinecone.io) is a managed vector database designed for speed, scale, and rapid deployment to production. It supports hybrid search and is currently the only datastore to natively support SPLADE sparse vectors. For detailed setup instructions, refer to [`/docs/providers/pinecone/setup.md`](/docs/providers/pinecone/setup.md). + +#### Weaviate + +[Weaviate](https://weaviate.io/) is an open-source vector search engine built to scale seamlessly into billions of data objects. It supports hybrid search out-of-the-box, making it suitable for users who require efficient keyword searches. Weaviate can be self-hosted or managed, offering flexibility in deployment. For detailed setup instructions, refer to [`/docs/providers/weaviate/setup.md`](/docs/providers/weaviate/setup.md). + +#### Zilliz + +[Zilliz](https://zilliz.com) is a managed cloud-native vector database designed for billion-scale data. It offers a wide range of features, including multiple indexing algorithms, distance metrics, scalar filtering, time travel searches, rollback with snapshots, full RBAC, 99.9% uptime, separated storage and compute, and multi-language SDKs. For detailed setup instructions, refer to [`/docs/providers/zilliz/setup.md`](/docs/providers/zilliz/setup.md). + +#### Milvus + +[Milvus](https://milvus.io/) is an open-source, cloud-native vector database that scales to billions of vectors. It is the open-source version of Zilliz and shares many of its features, such as various indexing algorithms, distance metrics, scalar filtering, time travel searches, rollback with snapshots, multi-language SDKs, storage and compute separation, and cloud scalability. For detailed setup instructions, refer to [`/docs/providers/milvus/setup.md`](/docs/providers/milvus/setup.md). + +#### Qdrant + +[Qdrant](https://qdrant.tech/) is a vector database capable of storing documents and vector embeddings. It offers both self-hosted and managed [Qdrant Cloud](https://cloud.qdrant.io/) deployment options, providing flexibility for users with different requirements. For detailed setup instructions, refer to [`/docs/providers/qdrant/setup.md`](/docs/providers/qdrant/setup.md). + +#### Redis + +[Redis](https://redis.com/solutions/use-cases/vector-database/) is a real-time data platform suitable for a variety of use cases, including everyday applications and AI/ML workloads. It can be used as a low-latency vector engine by creating a Redis database with the [Redis Stack docker container](/examples/docker/redis/docker-compose.yml). For a hosted/managed solution, [Redis Cloud](https://app.redislabs.com/#/) is available. For detailed setup instructions, refer to [`/docs/providers/redis/setup.md`](/docs/providers/redis/setup.md). + +#### LlamaIndex + +[LlamaIndex](https://github.com/jerryjliu/llama_index) is a central interface to connect your LLM's with external data. +It provides a suite of in-memory indices over your unstructured and structured data for use with ChatGPT. +Unlike standard vector databases, LlamaIndex supports a wide range of indexing strategies (e.g. tree, keyword table, knowledge graph) optimized for different use-cases. +It is light-weight, easy-to-use, and requires no additional deployment. +All you need to do is specifying a few environment variables (optionally point to an existing saved Index json file). +Note that metadata filters in queries are not yet supported. +For detailed setup instructions, refer to [`/docs/providers/llama/setup.md`](/docs/providers/llama/setup.md). + +#### Chroma + +[Chroma](https://trychroma.com) is an AI-native open-source embedding database designed to make getting started as easy as possible. Chroma runs in-memory, or in a client-server setup. It supports metadata and keyword filtering out of the box. For detailed instructions, refer to [`/docs/providers/chroma/setup.md`](/docs/providers/chroma/setup.md). + +#### Azure Cognitive Search + +[Azure Cognitive Search](https://azure.microsoft.com/products/search/) is a complete retrieval cloud service that supports vector search, text search, and hybrid (vectors + text combined to yield the best of the two approaches). It also offers an [optional L2 re-ranking step](https://learn.microsoft.com/azure/search/semantic-search-overview) to further improve results quality. For detailed setup instructions, refer to [`/docs/providers/azuresearch/setup.md`](/docs/providers/azuresearch/setup.md) + +#### Supabase + +[Supabase](https://supabase.com/blog/openai-embeddings-postgres-vector) offers an easy and efficient way to store vectors via [pgvector](https://github.com/pgvector/pgvector) extension for Postgres Database. [You can use Supabase CLI](https://github.com/supabase/cli) to set up a whole Supabase stack locally or in the cloud or you can also use docker-compose, k8s and other options available. For a hosted/managed solution, try [Supabase.com](https://supabase.com/) and unlock the full power of Postgres with built-in authentication, storage, auto APIs, and Realtime features. For detailed setup instructions, refer to [`/docs/providers/supabase/setup.md`](/docs/providers/supabase/setup.md). + +#### Postgres + +[Postgres](https://www.postgresql.org) offers an easy and efficient way to store vectors via [pgvector](https://github.com/pgvector/pgvector) extension. To use pgvector, you will need to set up a PostgreSQL database with the pgvector extension enabled. For example, you can [use docker](https://www.docker.com/blog/how-to-use-the-postgres-docker-official-image/) to run locally. For a hosted/managed solution, you can use any of the cloud vendors which support [pgvector](https://github.com/pgvector/pgvector#hosted-postgres). For detailed setup instructions, refer to [`/docs/providers/postgres/setup.md`](/docs/providers/postgres/setup.md). + +#### AnalyticDB + +[AnalyticDB](https://www.alibabacloud.com/help/en/analyticdb-for-postgresql/latest/product-introduction-overview) is a distributed cloud-native vector database designed for storing documents and vector embeddings. It is fully compatible with PostgreSQL syntax and managed by Alibaba Cloud. AnalyticDB offers a powerful vector compute engine, processing billions of data vectors and providing features such as indexing algorithms, structured and unstructured data capabilities, real-time updates, distance metrics, scalar filtering, and time travel searches. For detailed setup instructions, refer to [`/docs/providers/analyticdb/setup.md`](/docs/providers/analyticdb/setup.md). + +#### Elasticsearch + +[Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) currently supports storing vectors through the `dense_vector` field type and uses them to calculate document scores. Elasticsearch 8.0 builds on this functionality to support fast, approximate nearest neighbor search (ANN). This represents a much more scalable approach, allowing vector search to run efficiently on large datasets. For detailed setup instructions, refer to [`/docs/providers/elasticsearch/setup.md`](/docs/providers/elasticsearch/setup.md). + +### Running the API locally + +To run the API locally, you first need to set the requisite environment variables with the `export` command: + +``` +export DATASTORE= +export BEARER_TOKEN= +export OPENAI_API_KEY= + +``` + +Start the API with: + +``` +poetry run start +``` + +Append `docs` to the URL shown in the terminal and open it in a browser to access the API documentation and try out the endpoints (i.e. http://0.0.0.0:8000/docs). Make sure to enter your bearer token and test the API endpoints. + +**Note:** If you add new dependencies to the pyproject.toml file, you need to run `poetry lock` and `poetry install` to update the lock file and install the new dependencies. + +### Testing a Localhost Plugin in ChatGPT + +To test a localhost plugin in ChatGPT, use the provided [`local_server/main.py`](/local_server/main.py) file, which is specifically configured for localhost testing with CORS settings, no authentication and routes for the manifest, OpenAPI schema and logo. + +Follow these steps to test your localhost plugin: + +1. Run the localhost server using the `poetry run dev` command. This starts the server at the default address (e.g. `localhost:3333`). + +2. Visit [ChatGPT](https://chat.openai.com/), select "Plugins" from the model picker, click on the plugins picker, and click on "Plugin store" at the bottom of the list. + +3. Choose "Develop your own plugin" and enter your localhost URL (e.g. `localhost:3333`) when prompted. + +4. Your localhost plugin is now enabled for your ChatGPT session. + +For more information, refer to the [OpenAI documentation](https://platform.openai.com/docs/plugins/getting-started/openapi-definition). + +### Personalization + +You can personalize the Retrieval Plugin for your own use case by doing the following: + +- **Replace the logo**: Replace the image in [logo.png](/.well-known/logo.png) with your own logo. + +- **Edit the data models**: Edit the `DocumentMetadata` and `DocumentMetadataFilter` data models in [models.py](/models/models.py) to add custom metadata fields. Update the OpenAPI schema in [openapi.yaml](/.well-known/openapi.yaml) accordingly. To update the OpenAPI schema more easily, you can run the app locally, then navigate to `http://0.0.0.0:8000/sub/openapi.json` and copy the contents of the webpage. Then go to [Swagger Editor](https://editor.swagger.io/) and paste in the JSON to convert it to a YAML format. You could also replace the [openapi.yaml](/.well-known/openapi.yaml) file with an openapi.json file in the [.well-known](/.well-known) folder. + +- **Change the plugin name, description, and usage instructions**: Update the plugin name, user-facing description, and usage instructions for the model. You can either edit the descriptions in the [main.py](/server/main.py) file or update the [openapi.yaml](/.well-known/openapi.yaml) file. Follow the same instructions as in the previous step to update the OpenAPI schema. + +- **Enable ChatGPT to save information from conversations**: See the instructions in the [memory example folder](/examples/memory). + +### Authentication Methods + +You can choose from four options for authenticating requests to your plugin: + +1. **No Authentication**: Anyone can add your plugin and use its API without any credentials. This option is suitable if you are only exposing documents that are not sensitive or already public. It provides no security for your data. If using this method, copy the contents of this [main.py](/examples/authentication-methods/no-auth/main.py) into the [actual main.py file](/server/main.py). Example manifest [here](/examples/authentication-methods/no-auth/ai-plugin.json). + +2. **HTTP Bearer**: You can use a secret token as a header to authorize requests to your plugin. There are two variants of this option: + + - **User Level** (default for this implementation): Each user who adds your plugin to ChatGPT must provide the bearer token when adding the plugin. You can generate and distribute these tokens using any tool or method you prefer, such as [jwt.io](https://jwt.io/). This method provides better security as each user has to enter the shared access token. If you require a unique access token for each user, you will need to implement this yourself in the [main.py](/server/main.py) file. Example manifest [here](/examples/authentication-methods/user-http/ai-plugin.json). + + - **Service Level**: Anyone can add your plugin and use its API without credentials, but you must add a bearer token when registering the plugin. When you install your plugin, you need to add your bearer token, and will then receive a token from ChatGPT that you must include in your hosted manifest file. Your token will be used by ChatGPT to authorize requests to your plugin on behalf of all users who add it. This method is more convenient for users, but it may be less secure as all users share the same token and do not need to add a token to install the plugin. Example manifest [here](/examples/authentication-methods/service-http/ai-plugin.json). + +3. **OAuth**: Users must go through an OAuth flow to add your plugin. You can use an OAuth provider to authenticate users who add your plugin and grant them access to your API. This method offers the highest level of security and control, as users authenticate through a trusted third-party provider. However, you will need to implement the OAuth flow yourself in the [main.py](/server/main.py) file and provide the necessary parameters in your manifest file. Example manifest [here](/examples/authentication-methods/oauth/ai-plugin.json). + +Consider the benefits and drawbacks of each authentication method before choosing the one that best suits your use case and security requirements. If you choose to use a method different to the default (User Level HTTP), make sure to update the manifest file [here](/.well-known/ai-plugin.json). + +## Deployment + +You can deploy your app to different cloud providers, depending on your preferences and requirements. However, regardless of the provider you choose, you will need to update two files in your app: [openapi.yaml](/.well-known/openapi.yaml) and [ai-plugin.json](/.well-known/ai-plugin.json). As outlined above, these files define the API specification and the AI plugin configuration for your app, respectively. You need to change the url field in both files to match the address of your deployed app. + +Render has a 1-click deploy option that automatically updates the url field in both files: + +[Deploy to Render](https://render.com/deploy?repo=https://github.com/render-examples/chatgpt-retrieval-plugin/tree/main) + +Before deploying your app, you might want to remove unused dependencies from your [pyproject.toml](/pyproject.toml) file to reduce the size of your app and improve its performance. Depending on the vector database provider you choose, you can remove the packages that are not needed for your specific provider. Refer to the respective documentation in the [`/docs/deployment/removing-unused-dependencies.md`](/docs/deployment/removing-unused-dependencies.md) file for information on removing unused dependencies for each provider. + +Instructions: + +- [Deploying to Fly.io](/docs/deployment/flyio.md) +- [Deploying to Heroku](/docs/deployment/heroku.md) +- [Deploying to Render](/docs/deployment/render.md) +- [Other Deployment Options](/docs/deployment/other-options.md) (Azure Container Apps, Google Cloud Run, AWS Elastic Container Service, etc.) + +Once you have deployed your app, consider uploading an initial batch of documents using one of [these scripts](/scripts) or by calling the `/upsert` endpoint. + +## Installing a Developer Plugin + +To install a developer plugin, follow the steps below: + +- First, create your developer plugin by deploying it to your preferred hosting platform (e.g. Fly.io, Heroku, etc.) and updating the plugin URL in the manifest file and OpenAPI schema. + +- Go to [ChatGPT](https://chat.openai.com/) and select "Plugins" from the model picker. + +- From the plugins picker, scroll to the bottom and click on "Plugin store." + +- Go to "Develop your own plugin" and follow the instructions provided. You will need to enter the domain where your plugin is deployed. + +- Follow the instructions based on the authentication type you have chosen for your plugin (e.g. if your plugin uses Service Level HTTP, you will have to paste in your access token, then paste the new access token you receive from the plugin flow into your [ai-plugin.json](/.well-known/ai-plugin.json) file and redeploy your app). + +- Next, you must add your plugin. Go to the "Plugin store" again and click on "Install an unverified plugin." + +- Follow the instructions provided, which will require you to enter the domain where your plugin is deployed. + +- Follow the instructions based on the authentication type you have chosen for your plugin (e.g. if your plugin uses User Level HTTP, you will have to paste in your bearer token). + +After completing these steps, your developer plugin should be installed and ready to use in ChatGPT. + +## Webhooks + +To keep the documents stored in the vector database up-to-date, consider using tools like [Zapier](https://zapier.com) or [Make](https://www.make.com) to configure incoming webhooks to your plugin's API based on events or schedules. For example, this could allow you to sync new information as you update your notes or receive emails. You can also use a [Zapier Transfer](https://zapier.com/blog/zapier-transfer-guide/) to batch process a collection of existing documents and upload them to the vector database. + +If you need to pass custom fields from these tools to your plugin, you might want to create an additional Retrieval Plugin API endpoint that calls the datastore's upsert function, such as `upsert-email`. This custom endpoint can be designed to accept specific fields from the webhook and process them accordingly. + +To set up an incoming webhook, follow these general steps: + +- Choose a webhook tool like Zapier or Make and create an account. +- Set up a new webhook or transfer in the tool, and configure it to trigger based on events or schedules. +- Specify the target URL for the webhook, which should be the API endpoint of your retrieval plugin (e.g. `https://your-plugin-url.com/upsert`). +- Configure the webhook payload to include the necessary data fields and format them according to your retrieval plugin's API requirements. +- Test the webhook to ensure it's working correctly and sending data to your retrieval plugin as expected. + +After setting up the webhook, you may want to run a backfill to ensure that any previously missed data is included in the vector database. + +Remember that if you want to use incoming webhooks to continuously sync data, you should consider running a backfill after setting these up to avoid missing any data. + +In addition to using tools like Zapier and Make, you can also build your own custom integrations to sync data with your Retrieval Plugin. This allows you to have more control over the data flow and tailor the integration to your specific needs and requirements. + +## Scripts + +The `scripts` folder contains scripts to batch upsert or process text documents from different data sources, such as a zip file, JSON file, or JSONL file. These scripts use the plugin's upsert utility functions to upload the documents and their metadata to the vector database, after converting them to plain text and splitting them into chunks. Each script folder has a README file that explains how to use it and what parameters it requires. You can also optionally screen the documents for personally identifiable information (PII) using a language model and skip them if detected, with the [`services.pii_detection`](/services/pii_detection.py) module. This can be helpful if you want to avoid uploading sensitive or private documents to the vector database unintentionally. Additionally, you can optionally extract metadata from the document text using a language model, with the [`services.extract_metadata`](/services/extract_metadata.py) module. This can be useful if you want to enrich the document metadata. **Note:** if using incoming webhooks to continuously sync data, consider running a backfill after setting these up to avoid missing any data. + +The scripts are: + +- [`process_json`](scripts/process_json/): This script processes a file dump of documents in a JSON format and stores them in the vector database with some metadata. The format of the JSON file should be a list of JSON objects, where each object represents a document. The JSON object should have a `text` field and optionally other fields to populate the metadata. You can provide custom metadata as a JSON string and flags to screen for PII and extract metadata. +- [`process_jsonl`](scripts/process_jsonl/): This script processes a file dump of documents in a JSONL format and stores them in the vector database with some metadata. The format of the JSONL file should be a newline-delimited JSON file, where each line is a valid JSON object representing a document. The JSON object should have a `text` field and optionally other fields to populate the metadata. You can provide custom metadata as a JSON string and flags to screen for PII and extract metadata. +- [`process_zip`](scripts/process_zip/): This script processes a file dump of documents in a zip file and stores them in the vector database with some metadata. The format of the zip file should be a flat zip file folder of docx, pdf, txt, md, pptx or csv files. You can provide custom metadata as a JSON string and flags to screen for PII and extract metadata. + +## Pull Request (PR) Checklist + +If you'd like to contribute, please follow the checklist below when submitting a PR. This will help us review and merge your changes faster! Thank you for contributing! + +1. **Type of PR**: Indicate the type of PR by adding a label in square brackets at the beginning of the title, such as `[Bugfix]`, `[Feature]`, `[Enhancement]`, `[Refactor]`, or `[Documentation]`. + +2. **Short Description**: Provide a brief, informative description of the PR that explains the changes made. + +3. **Issue(s) Linked**: Mention any related issue(s) by using the keyword `Fixes` or `Closes` followed by the respective issue number(s) (e.g., Fixes #123, Closes #456). + +4. **Branch**: Ensure that you have created a new branch for the changes, and it is based on the latest version of the `main` branch. + +5. **Code Changes**: Make sure the code changes are minimal, focused, and relevant to the issue or feature being addressed. + +6. **Commit Messages**: Write clear and concise commit messages that explain the purpose of each commit. + +7. **Tests**: Include unit tests and/or integration tests for any new code or changes to existing code. Make sure all tests pass before submitting the PR. + +8. **Documentation**: Update relevant documentation (e.g., README, inline comments, or external documentation) to reflect any changes made. + +9. **Review Requested**: Request a review from at least one other contributor or maintainer of the repository. + +10. **Video Submission** (For Complex/Large PRs): If your PR introduces significant changes, complexities, or a large number of lines of code, submit a brief video walkthrough along with the PR. The video should explain the purpose of the changes, the logic behind them, and how they address the issue or add the proposed feature. This will help reviewers to better understand your contribution and expedite the review process. + +## Pull Request Naming Convention + +Use the following naming convention for your PR branches: + +``` +/- +``` + +- ``: The type of PR, such as `bugfix`, `feature`, `enhancement`, `refactor`, or `docs`. Multiple types are ok and should appear as , +- ``: A brief description of the changes made, using hyphens to separate words. +- ``: The issue number associated with the changes made (if applicable). + +Example: + +``` +feature/advanced-chunking-strategy-123 +``` + +## Limitations + +While the ChatGPT Retrieval Plugin is designed to provide a flexible solution for semantic search and retrieval, it does have some limitations: + +- **Keyword search limitations**: The embeddings generated by the `text-embedding-ada-002` model may not always be effective at capturing exact keyword matches. As a result, the plugin might not return the most relevant results for queries that rely heavily on specific keywords. Some vector databases, like Elasticsearch, Pinecone, Weaviate and Azure Cognitive Search, use hybrid search and might perform better for keyword searches. +- **Sensitive data handling**: The plugin does not automatically detect or filter sensitive data. It is the responsibility of the developers to ensure that they have the necessary authorization to include content in the Retrieval Plugin and that the content complies with data privacy requirements. +- **Scalability**: The performance of the plugin may vary depending on the chosen vector database provider and the size of the dataset. Some providers may offer better scalability and performance than others. +- **Language support**: The plugin currently uses OpenAI's `text-embedding-ada-002` model, which is optimized for use in English. However, it is still robust enough to generate good results for a variety of languages. +- **Metadata extraction**: The optional metadata extraction feature relies on a language model to extract information from the document text. This process may not always be accurate, and the quality of the extracted metadata may vary depending on the document content and structure. +- **PII detection**: The optional PII detection feature is not foolproof and may not catch all instances of personally identifiable information. Use this feature with caution and verify its effectiveness for your specific use case. + +## Future Directions + +The ChatGPT Retrieval Plugin provides a flexible solution for semantic search and retrieval, but there is always potential for further development. We encourage users to contribute to the project by submitting pull requests for new features or enhancements. Notable contributions may be acknowledged with OpenAI credits. + +Some ideas for future directions include: + +- **More vector database providers**: If you are interested in integrating another vector database provider with the ChatGPT Retrieval Plugin, feel free to submit an implementation. +- **Additional scripts**: Expanding the range of scripts available for processing and uploading documents from various data sources would make the plugin even more versatile. +- **User Interface**: Developing a user interface for managing documents and interacting with the plugin could improve the user experience. +- **Hybrid search / TF-IDF option**: Enhancing the [datastore's upsert function](/datastore/datastore.py#L18) with an option to use hybrid search or TF-IDF indexing could improve the plugin's performance for keyword-based queries. +- **Advanced chunking strategies and embeddings calculations**: Implementing more sophisticated chunking strategies and embeddings calculations, such as embedding document titles and summaries, performing weighted averaging of document chunks and summaries, or calculating the average embedding for a document, could lead to better search results. +- **Custom metadata**: Allowing users to add custom metadata to document chunks, such as titles or other relevant information, might improve the retrieved results in some use cases. +- **Additional optional services**: Integrating more optional services, such as summarizing documents or pre-processing documents before embedding them, could enhance the plugin's functionality and quality of retrieved results. These services could be implemented using language models and integrated directly into the plugin, rather than just being available in the scripts. + +We welcome contributions from the community to help improve the ChatGPT Retrieval Plugin and expand its capabilities. If you have an idea or feature you'd like to contribute, please submit a pull request to the repository. + +## Contributors + +We would like to extend our gratitude to the following contributors for their code / documentation contributions, and support in integrating various vector database providers with the ChatGPT Retrieval Plugin: + +- [Pinecone](https://www.pinecone.io/) + - [acatav](https://github.com/acatav) + - [gkogan](https://github.com/gkogan) + - [jamescalam](https://github.com/jamescalam) +- [Weaviate](https://www.semi.technology/) + - [byronvoorbach](https://github.com/byronvoorbach) + - [hsm207](https://github.com/hsm207) + - [sebawita](https://github.com/sebawita) +- [Zilliz](https://zilliz.com/) + - [filip-halt](https://github.com/filip-halt) +- [Milvus](https://milvus.io/) + - [filip-halt](https://github.com/filip-halt) +- [Qdrant](https://qdrant.tech/) + - [kacperlukawski](https://github.com/kacperlukawski) +- [Redis](https://redis.io/) + - [spartee](https://github.com/spartee) + - [tylerhutcherson](https://github.com/tylerhutcherson) +- [LlamaIndex](https://github.com/jerryjliu/llama_index) + - [jerryjliu](https://github.com/jerryjliu) + - [Disiok](https://github.com/Disiok) +- [Supabase](https://supabase.com/) + - [egor-romanov](https://github.com/egor-romanov) +- [Postgres](https://www.postgresql.org/) + - [egor-romanov](https://github.com/egor-romanov) + - [mmmaia](https://github.com/mmmaia) +- [Elasticsearch](https://www.elastic.co/) + - [joemcelroy](https://github.com/joemcelroy) diff --git a/datastore/__init__.py b/datastore/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/datastore/__pycache__/__init__.cpython-310.pyc b/datastore/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c3183cc4c5b839e1d9357162bba72c17e77716b GIT binary patch literal 153 zcmd1j<>g`kf|WIoQ$X}%5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HGenx(7s(x}o zesNxEk$!SUVo7>IiEdG9Nl|8MSz?ZEK~8CUW}bdZVo73gNq$kPetdjpUS>&ryk0@& WEe@O9{FKt1R6CHV#Y{kgg#iEy)g+t% literal 0 HcmV?d00001 diff --git a/datastore/__pycache__/datastore.cpython-310.pyc b/datastore/__pycache__/datastore.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..258b98868790b86c79f8fd1295616cfd5d41aae6 GIT binary patch literal 3346 zcmcgu&2JmW6`z@1E|(NZQ6K(@o21*?LCivyb7>ESW2Cj?CPky7c7Xzm28-3sNLqV8 zn3<()5fqSALX%4Z^wP5feMP&m}^>#?IpBLgy_g>Je0&aGH^vhBRj(qu6Jele?jtH^N5lg`SZ) zSu$AtTW z9y#F}ckYov>l-+o448I)_3K-@7jLUd#z~cnYOmx2N4vMvq|)y1QdMdH_roeJi#XdF zc-p^RCZk*wmG0K9TYID8fj(b%-xF2L<0`(BW|fe-@rRL+2YSi;-4$w-ReIHQ{*+dG zZ|B>B^R(C>kmu!`m?4osRWjp39eb z=hzLGVLguZpBwA)o>{jdS}lq{evU7L2Ig#-*@yNj{I9_OnpwHFu{0m6G#DaDp<)u1TdH?Txi`9KtrO2ZBo0_#f9PXaj-aStLiG`?$bI@T z*`b_rcI;2+ZE{3EBkuw@?+{8VHlY)C#15TL$YW>Xd`|5MsN%-pm!us`zdyzggbLCk zh=UBABPe%*nRY>3a2QfTRw}6WL=K&*#8!X~u^lV1Ios$?Dq%SnnW$jHILpjD@d!2r zcL?@H0>-Q0AvlTMVd@w`%7d%vPEd$MC>6_t4cKHT3a)~(Ff;AafNu{ruwN{y1j`=6 zJfY@_+%@=}VGo?NFf9QTW*>u=2W1V4x(d}UnUMGUhjc>k6UjaSuo2SxK3~Ns)rdtYzXKffb}Uue7L5qN01C2{YtKq#3yy$^Z1WB6*NdM}?JAM&JR#q{ zd3~?U#r0%ZszS)?$zELT4y$Y688Q|7advH(jds)GI^KdppPIKehX=ZS1FteE^Wn{x z(V+8Cd4x4x%Ki<7y3{>kj{DR*8DE*X<>qLJ7rl8SE0Z`=H=$8)vNdpZGgb#hl9t-r zjo}ic?82tH8QE0>SN;h4vX9jYj(C>u5*3h_uzJOa?fg|}E1b+ebX#o-s{N;Z((d-z zxPMw9`BRvd;04tmw(;`5gz_)EHDtqI=zxwto_XULZhhLl1FPZx<>cSfx8N$*w#w?= ze3%K0t%AQTWhn>DqJ$P%U<^74jQj~y8&DMT98hVFSLR4eQP#~5Aoiw0JqJev7T_X; zL*0PtBO4Tm4GM>>A`lAbp~D>r6{G^6o;XJg1ID2{A&=R_HQ~X1hk!pf#(#Ygh*Jd& zXx7Vt>kuVu(1P|Xir~xxkYj?F(ms!?WDkQu?edFPpc3%o7xB{p)9#^-=sbp>4a-l< zL<1<0v0)Ads4v1aiCjJn^{XJmAga)jR>}DC9B8xlEDAgqEl`st6r;`0pkcIG`7=AD zh&HDwVE>qYPQHNLHDM|Jf__G)@q+2rEcaQJne4z8+U1a;2hM`p0}!93`LT)~NI->b= zC<;$wANCqP^_b7RXMK0Pdcaq&5*5~OGSVY`lAH5C7tL2*~)kF8i)0~v+sFn) z-Ge8ikY?X%hBLUPc*`R3g|C zsbb=*#HXc%NBlG{Anznzr^(0K-7d>aqMi%7&m;6Q3}9+gzktdojJYQsWwx;PGj{0; zz2vjr%anP{VVGv0wi$coIqbil%bv1E|2v6$4A!+1ZzmEtVYJj(r+K>-ZhI?)(oD0!jq{ literal 0 HcmV?d00001 diff --git a/datastore/__pycache__/factory.cpython-310.pyc b/datastore/__pycache__/factory.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4cf3f6c06aa6de3dac31c7596f03dd43d6230945 GIT binary patch literal 2183 zcmZ{l&yU+g6vsWbT;RQl<4jT3k|%HG^PQPD@4az?YPF=n^XQMi z=&wah`x86rV?gH}c*C2}P>m9(pSRuTzuezA=vts&}=9^*3m>21$ws zPULi>K(PCXC0H~Teh<<7se@s{`wP6`&qUL{CXx09d8SkHoW$B0Y%(Tc^#kpkoPm() zk9DyFTN~8mhG)j$#u<64b&=(Oy)2omfxRJFf#ST1E%U?-B*c-5=L7BDMibzqTXE4=Ql#Cc%(XRFV(yKtiS zXa25&=3Hvl_?ovK7eG@;=dT0%R056oKam$SD>={axA3$|1>d?syK6 z+J|T?Kw;$itQYtU*y@ASR`3(%Ok5|D__NerV9Rs)WE|p-A4y9=Q@YBfc(Gw7?chcU$orR>zxD$dR^JDW+9aso+kLiiy!ZNjc2X{Jm zGceu#)CVU=fruEjC#(mT)uwQ3(d*mxwBNFi#HkJWu!FuG4Vm2!I1iq<{@}JPbJ(!4- zMY@90r6-f&Q4uuFrqn;GAon)N}EFpoVAu#0v zlPNGw0y7{mssckLFa!dRCeUGlJ_s9{A2snR{QUD~dl-1E-GhMmOtgDLCmM{RTksbt zTsCp|tq~s&T)&-d-|jnjHBVck)1(TQW8roV)(a^#`d1ZFA-Z0I)|$7vVyoj|*XEl4 zjc0Rl+^{6oiB3wy{8zjV8#T;iJ#(y;SwaUU_OU^gJgCyV24hL#Eia&B&fdoVg%Gc9 JMJtds<3Asbhxz~j literal 0 HcmV?d00001 diff --git a/datastore/datastore.py b/datastore/datastore.py new file mode 100644 index 000000000..ff0c79dd8 --- /dev/null +++ b/datastore/datastore.py @@ -0,0 +1,86 @@ +from abc import ABC, abstractmethod +from typing import Dict, List, Optional +import asyncio + +from models.models import ( + Document, + DocumentChunk, + DocumentMetadataFilter, + Query, + QueryResult, + QueryWithEmbedding, +) +from services.chunks import get_document_chunks +from services.openai import get_embeddings + + +class DataStore(ABC): + async def upsert( + self, documents: List[Document], chunk_token_size: Optional[int] = None + ) -> List[str]: + """ + Takes in a list of documents and inserts them into the database. + First deletes all the existing vectors with the document id (if necessary, depends on the vector db), then inserts the new ones. + Return a list of document ids. + """ + # Delete any existing vectors for documents with the input document ids + await asyncio.gather( + *[ + self.delete( + filter=DocumentMetadataFilter( + document_id=document.id, + ), + delete_all=False, + ) + for document in documents + if document.id + ] + ) + + chunks = get_document_chunks(documents, chunk_token_size) + + return await self._upsert(chunks) + + @abstractmethod + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a list of list of document chunks and inserts them into the database. + Return a list of document ids. + """ + + raise NotImplementedError + + async def query(self, queries: List[Query]) -> List[QueryResult]: + """ + Takes in a list of queries and filters and returns a list of query results with matching document chunks and scores. + """ + # get a list of of just the queries from the Query list + query_texts = [query.query for query in queries] + query_embeddings = get_embeddings(query_texts) + # hydrate the queries with embeddings + queries_with_embeddings = [ + QueryWithEmbedding(**query.dict(), embedding=embedding) + for query, embedding in zip(queries, query_embeddings) + ] + return await self._query(queries_with_embeddings) + + @abstractmethod + async def _query(self, queries: List[QueryWithEmbedding]) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + raise NotImplementedError + + @abstractmethod + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything in the datastore. + Multiple parameters can be used at once. + Returns whether the operation was successful. + """ + raise NotImplementedError diff --git a/datastore/factory.py b/datastore/factory.py new file mode 100644 index 000000000..1103e0a60 --- /dev/null +++ b/datastore/factory.py @@ -0,0 +1,72 @@ +from datastore.datastore import DataStore +import os + + +async def get_datastore() -> DataStore: + datastore = os.environ.get("DATASTORE") + assert datastore is not None + + match datastore: + case "chroma": + from datastore.providers.chroma_datastore import ChromaDataStore + + return ChromaDataStore() + case "llama": + from datastore.providers.llama_datastore import LlamaDataStore + + return LlamaDataStore() + + case "pinecone": + from datastore.providers.pinecone_datastore import PineconeDataStore + + return PineconeDataStore() + case "weaviate": + from datastore.providers.weaviate_datastore import WeaviateDataStore + + return WeaviateDataStore() + case "milvus": + from datastore.providers.milvus_datastore import MilvusDataStore + + return MilvusDataStore() + case "zilliz": + from datastore.providers.zilliz_datastore import ZillizDataStore + + return ZillizDataStore() + case "redis": + from datastore.providers.redis_datastore import RedisDataStore + + return await RedisDataStore.init() + case "qdrant": + from datastore.providers.qdrant_datastore import QdrantDataStore + + return QdrantDataStore() + case "azuresearch": + from datastore.providers.azuresearch_datastore import AzureSearchDataStore + + return AzureSearchDataStore() + case "supabase": + from datastore.providers.supabase_datastore import SupabaseDataStore + + return SupabaseDataStore() + case "postgres": + from datastore.providers.postgres_datastore import PostgresDataStore + + return PostgresDataStore() + case "analyticdb": + from datastore.providers.analyticdb_datastore import AnalyticDBDataStore + + return AnalyticDBDataStore() + case "elasticsearch": + from datastore.providers.elasticsearch_datastore import ( + ElasticsearchDataStore, + ) + return ElasticsearchDataStore() + case "kdbai": + from datastore.providers.kdbai_datastore import KDBAIDataStore + + return KDBAIDataStore() + case _: + raise ValueError( + f"Unsupported vector database: {datastore}. " + f"Try one of the following: llama, elasticsearch, pinecone, weaviate, milvus, zilliz, redis, or qdrant" + ) diff --git a/datastore/providers/__init__.py b/datastore/providers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/datastore/providers/__pycache__/__init__.cpython-310.pyc b/datastore/providers/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fbf9a170f3a8e0c24ef020a578fa6c421a39bfec GIT binary patch literal 163 zcmd1j<>g`kf|WIoQ$X}%5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HUenx(7s(x}o zesNxEk$!SUVo7>IiEdG9Nl|8MSz?ZEK~8CUW}bdZVo73gNq$kPenC-wS!POVQL%n} gd}dx|NqoFsLFFwDo80`A(wtN~kom<-K!Sw<0Kiiyvj6}9 literal 0 HcmV?d00001 diff --git a/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc b/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee9a8147351c0c88d7eb81330dc97c22191cbdcd GIT binary patch literal 7184 zcmb_hOKcoRdhV|7>FMct@F`N1{AkOzq_HJRyXyqIisG0iDT}d0X-Ud<#;XikQ$@0= zd8xWb*332q+tR{XAj)HN%mx_dW+10rbIc*PAm_r~a)|@vvWoA^h$w)1W``8qYm2zcfD^_Bc^_9X&kp`U^dNJnE58d+-7;ZkfEq z$9`_{aV<}1d6G|}d`ipHy8MWiXS6)4<)d1j)ABKX9PMAy^2@sX6_U5z${WJmd9#0# zzsmhRRyj4uy~a-`Ax`g^OKb`{8Z&EKV6yU<;pq!R^_~~ z``;1v&Ug9S{LEwX|4}+i`uP0Mb9-j+y$=k2j-P*M@bhBofmL~jo9jmTJKvBUt(HyY z)LUCyLY8f1Ei}8zUJ7fmvaf_utlVquIBYe8I+|rVosho+VIpo-JI(N3H4Ymhii1WQ zg}J354%XwA6y>ZcF12c%hG@o%+nwfZb>vX?s)z%Q#>!c5b!1JbnPK&?=2BRXg;e<; zc7*J%iKtVL)uhgR9LC$rja!2Au(`G0QGbT&)@v9*Z|1|L_ZL>qE?!w#UfuBT3K?Mz z7yRDJVyjcaGLKaBmj<;UB? z=b|l|Tr_K;h~|5x>)j7OIiULT3#!}Q+xLD8&C0FOnpH!toG6xBC5$y?-VkFrH6*z81)<$ptG`LaWC$Tj})GYd@8}G^j7p{s3w*D z)@C|y+NxYyMmmcJnn0t~k@a5bKpFDNt4R^Wf>#3=62>WdbBk1hZSW~ex`)G3PSC;f z%ih?~4E(e}jq7c!E?&EGWqEO9<=UzmZ($FDaAX0II+C`zzPz@+vc9pry0~0jT3J(0 z+E7iV)hnw@%b!%QFRU$GT~||S+4}Or+T!J5;l$GNrG*<;HmVC(KDf5FvT^z9H!j@c z8y`t%IFL9bW#1LGNLknzatI#N@@F^etsws1cgs0Bi#BqGk~wP4LN1R|?ieML6$6(+1rlLHtyID zt8vH^cu(Lxse4Usx_pvPLDv+w04Ou6q*r!n2n5Ot;V}2A+FTte;*M;t))1#gKN}Lo zw?#bBBP5BL7*(V9R*Xqgl!)1mMN_AVKel!m${k&9CaiDo=}3aIER~@o!`(g7;KWFG zoPIWK@iC&@x?vl!+g&t`T?BODOuUtLL^`4RNm4ZbeNY&(*erc&i`to?R@?V&S@rBv@=PhHGZ5cm>-Sv$92scodz z##v&Mr3~zhB^KFCZ1rt!9k3xA8qVxy(A!QjqxMEWlVo-rZJAj}E^IT)GZ$fVT5=#| zc5+(IYS|-slkGZ>j6O@y(=_h9eaHLC02sJD_t1^=+=~m3VE=LPfwhG9ZZ^r{>wMRZ zOZ_pPM=K+7sb zMGDh5Z#DKA-EU z2ZW*Byx>y=9-;-pGzE6JqyL$ZVlW87=STDFxoC@KAVmc|⋼x!H8d^Z@pW1S+z+ z*#-YVjGKTr)v(H=A7KYVr7?vkdI`yvkr+3nVf~o4j#- zeR*x8`u@TO!twe_Wx320n?JA2@M}{?N)0x08TyoWk;YkTHQMj~8-0Xgv|}(DL!QKNPAE`(ucNyC0&>=cgH@%(BUi5|PNi*a*fIOejcJL&;_&EyK2DKk#T zM~J8gDX&2KC7xf=dQ2PgL%e?Dx8zmSmd$TyK&hhDk#tz)e^B{#B)y~in{+FPYujXc zQP>lH?|51xxSv);9UWdaJN0_Ecj{6Q)=@Pw%RwV4z?yk<#@DES!C&p2T+wDrEfK)# zqNbVKrtUs!_T%01ODYq_q7ljOV^|<^ZKB9&2(iQFW=oA#Q=D%MIlnuSa@C=jn$#Im zkrN|wpOHaxODL-@n({K$v1VIk0x5&8Vr`xtI4((|!ZwGC%HN|#S&X;SXh!n)^@vjU zQ|5-eh`js*O5W2on=RQ0;&MqYP}v7mmQ8&kQcfy>#%d}~R--anRu%}L%Id`xk;-U6 zd81KBit$aAZ;H?K?5fCE7?C7`lkP4VLu$*}YHFWE=9^zkt6-@R^Z=%GUr*3B2nr72zQ!*JlYEI`#DxpUj86CTn9Y?g(Q8GOZjab?I z;IooGc_>0=P(UuA*%%obnSRHRP6)3E5h>Fs**A5hoJ}KTf?I`-Dc?*iZr(NIYcV3_ z1F$pB5I0JRogh|f2`*o@aNN{9SSMvmR`C_NMhSUxIg{=NjZBrEvmEQT=&B4@1sIEV zjD7F8f%dp+Fe36>*RoBUO*0p)p@bD=pWCeW%Jb0hoboL3ARO!tt%n6|v>uuS0-XHcT7OtFf>1lhBO3_Su6 zQ@D9sNb-mS`hRo4(VEj^IRZ~AV8~#nBEXCyt#&`w$ak@H@;s75AXq>FasR)>6P?8F zfsdU4?*Uhb&7F8;?3jHPTd@uH1TMdYh~LlRhJ~2D%h_YFb`8$foVHAkzTcsJW zj9m8z;0(5A8D2lnGbwu`&XCxe=iB#f;tAk?8E_iL9dI3s(gzIu=Mroi>??7=su&nm zai@f5EOBnrVJkal?2J=e@T%g@1Q=O%i}4)y9765YO_YLR@%%+2o=LKao8*uyJhpf9Nv1!Wv~hw6jNmciC#={DFyx9?sjie$s$X7KEb@ zkQPBhM%AhuCyf-rC9!=y+HxTsbSWKNbue~{89;R_Tp zO|O`SCY)vIP6}A2gU1MnunTmOtBa~u_AWsZ89#uXdDcmnAj$r`R2ssxojGO!@Xcf9 zNycpU3~*0?Wid1TbG|J&CDuFhJa}pC`?TiJM-TZJtuP^&CS(Um4H2>j<^dw6Ar%`; zlqOv_Q~n9bqseJn^981qa**=>F{pj6wF-M0BUQ8~DjP&y+@ZCUvlRf_B!Ylm#E4pS zhhM}<^w)KjW`0h(rt=s;L>tdOpBcB`A2+>cw%to_fewT?y+ZO4sp}z89v5{Hi)v7> z*Jwe8KMHvSLjQm#+Cc&knoTS@K|s_;prb2@zD2MT;6Ot690W*QUm2u%z>U*=X8my2LReNIZjZ2-TCRjl|jJtjq4KFC`g04_O*t#O#=)L{| zdwZU@fsnb{6XlnfN$OAbwg^&2radinyc(*9v39gZ^3SQ$A|-myM;i}1q!;fiT6((4 zf;qc3^D-WDZ11T9jxypJ&u>K9vuv&+^sla#r|FDO*Fn{)^5D2F-hs1JRiTRA4eDu) zq?5laQ*wzC+Am2PC26N*ixN6zNIK0+ixMIL`!**3jI#8f5xQ;z`}!H>_a`-)nVd(( z7kIRnx(3VGPvCt|nCJcHiSM((e&(3$na8}RY|3HmsbhIh*r(*1_P3tSvnP(tzGa!x ze`{Uk-%<8X)M_f$isWM&fYU}u4?7P`O++v zP1o)+OJWgc$-4wd^Eey|O_|gbofGxt3Kgc3q^m?##PW)IG@riG#nVeh?xU9{MM>?O zgq*67vZ7i&gx$#>P%};Jfw6;2bnI1rMPHrk*rL3Th>xYRO*h_(;c?a%FE3wRP+8Hu z8%ivPwS_Aoy{$eeJweIql)Qli*Z70G*X2u#*H+gz)^4P?y}4oeRh1u#ODk8?)4<^3 z_aod4Ut6O);_B+c)n)m|q|jN{WG?0Ww8#J3<}3GNYJUXNM)WsGT!Rpr{tDL70p)%J z(CxBGl<0kb#-1_9HIZkde9k6|cmi+ut={%8O6NfMtpfgROIw8q1%W@JQYJh z{YeEW5~qVSc^ZNYc^ZQzc+xR*+!C}6J^V)vII@F|7RXYkiA3MHC$BZ2EgB1<8t(ZO4*OZ=322Q3)hK<`im&fef| z!r3P5{u4RZJdd+L&2<)gl<6vlDxW;d+drkD=kV9BVD}5us^#l;)Y|g`wH!RPqgKxg z)T*x@UC_rj1o!fd!F_yFu$ONR?&qDsKE5T`53|S29Vm{2#10l?eCu6THJ|@y`R<+L z=RJ3J?8xvT8oi46UGF2lO=$cSPU2_q*RS9JPfa3U``0)+?xQqQEIBhHh(1O$3?>#e zW+WPsHRfDYk~PbPlpIYa!Z9djoS%>KhapfeCqwgz=t4-2#sx_Z$5W7K9SO_fNjWJB zKC@;YNk-=5LP8#%olo4*nyaGc1v$(^Va+s|oEIa4<}79xbIwF#vLI?T7v}|WaYB&h zW3tvjB0r4Evw`?^f#;)%nQ}$a49=U3KnIqbXGewx$Mz4O8w-q2aW@4~f-(5HrLp1U ze2nK3NtuhrQ%OW8))%*F&!jP7I!()Ef1)$-v;m@MtlSnN3LV zd~Jb!@HGb{icApVA*3-kg@~jXBw55O&&!J`K{HRsl3{t^kk6_yvald)HGE;2Ls4F{ zN@O*0kcPiWk7|Z_F{arfq7aq^J`{$Hbv?;1io2kZ2>eTzwGett1MuEP0>YvqNDGE( zil+pIr+LFP!!z$2gGSycm;^>J3l>+Y`ZQe*^EBi!|AAXg>FG@2`=XNnuNSdcvb z_$U(lb|bl|TmdwQ_GLzHDW}Y_#V~J6Gk=5rmVRms%unGUEHgi1-YIDrJc12UGrr^+ z#>Wbfuz+Kef`pN-udh$D#*&e6Y&I#$(GNkl(U@6TPWcS*gd~l@;HOzqVp2{P;y!_$ou*GcLbFO#27#X~Nuat^~7X{wi``n^lXlOp3ki7mY z&n<&ndDn|~xYy5lv3T+J!jm+i$E8#_;az@yE7csN#dswHh+a>|Uc7n~##3(oPpvJ7 zXP!|V7=~q8JTJuY5NE{XdeW55krAjWajbb?Ak1h$Q9u`uaZT!0Qm@X*d3!Y%O8IIK8#@W{Z?<>jl-<-feNYcLYQTMjn! zo}yTh_HZ)Zn10P#N?LLSL@_Cnty2!uCCKde-Bcp3e_|*{wJ)W}O#R=f%}mAF=gHLtmEdSJ{4r z?T6^vp4+`2_WrzY9a1|~wnJe%zB3`Gdp(#(wvM)Mkj>ftEhejHzH^f{4rSQ^l^syn zftk{H53BCOt0TA0Vve2b`yMvz-fGyLZRk=Py0UDy%62Q{e)3gaYaY?o zrZRcNHrzU=xQ^eu2n6mddqQPTDC~(`L*weJPvFWMp#pwdkfUi;mRex~J{USNY(T#; z*oOBReq(nHcN>1wZG^C9ieQ~os*;>o!n_Cn$8Uk;Jc}q$KtNuWEI@?jN@1Sj>1xX- zQz?UiiGEc}hGiOLNl7X`TOy{P!hX3z3i5`hBts>~l8h|2kDt|j0NdC&i9jONmdk)d z8UQI;Urw1T$vK|M5G%i&r-#xzda|=$Gblp80c|ZCeguk){w&KbpDFBu$-I=31kk_r zwSdE1RI-Z)q0d&ria~Kk@|R-xTor2dU_<2!sHnXhHdd~TR2m&uuloGlAcxO7mz?IR z@+7R&M-#XQ%h4GDg(gf{b}#~7dRnXKsF1X0Cy)Fd5(u3hzWQ`mSYE6RJI zb-)4c9YGWdoe=oG()gAZ-|e|_mBX^ne_%Xuk^`~hzjl&~@_z1GCve0)SU7!PeC8y8 zm zXw=&po#Mrlz)~~mEXBhR5nsmS6-@AX5KjToOw&m*9+rKKcp9e#a2m}|i$f5Qu=A=8(P+1tYJd9`_Z}e}$_kKzMZ(IjNK`j$B&?)*d{S875Kcv4U z^gn?H>Hi=Ur@u+k-=tTEa;)Rl*@tZV7TdldW?8SwdKK17Fmi8}-KVnq6n0;sP}>&U zmSta3*_V{!T?8{H1~Z)$z-;iLYjn#s`el9Abyjtq&9diI_MF0=%QZHyj+K8!aC1UH zYKK9+Kj<6mNB8?}L%oLkCwhkV7#?&`5Pq=72voCx_$9V=6}sUG#B==^>(==$e25?M>-H=BJR$O`Pl`uwSAufp+qkKkvvs{3%R;x?P;_x-Y z4Pj9;f`px~5XbrkstZ+@U25McORMw$3;0VS5ZFv6#5O549Z@K%k?t`lPU>+H*2MGD#2dl$t&AGZJrH;!rIyd^1#vZsI4UBwoDLZgh9XPu- zo_RUjbUG0H=z6ZIFZvy!l`k6tOT0AA= zI)#g;%u6zH7LQZX5oBfqjG5 z$h7o?IAzKhIw^!jj5vUJCAi@LlE953anr=BgB3TNU&fFMD19303uEVc2%wVYs(e5g z*S1R~FAF2sw-PHt;tp}jXplA{d)!CL&T1T;cFwc?7vw^M6 zzlQ%~9?sh@sG=qTvcIq*u#2J}uw`xH*}8*VVYSL7c??=e$wmi`rXtIk9k%>)Y~CHE zDs9`lJ2aZ=Q@Tv0Vb_#h6&N-63irygf!MhX#r_~vuydQsDRU)FhBv;rojZe;jdHnR zu;+PGISL3<5v$h80FC~Ipb@=nN}HC=X?ocryDR!r(t)Z{>xw1PrW@qslw0G?nF^h%SQ`8;7T!EV^VYkz>i*9C$^FSx%y*f8H6~{o%Q@vxb(v*b+9tN~ zHEA25wJUAoE1Y9;Pr24yX*F+BqLD|qB*trbf4NNBoVKK`Y1>`)Q;<2IVYx%D<(jlH zQ{nX}rh|8A$NLTn-FhS+tjI@mrD;za@9ucN0T@&}F5*`=K3X&Drm3V+3C$h~B@!VX zbiZ&SB8a=8#FA6jnw7Z>;m#NKF;9sWWozkN$kWChSb-L680_Y zC9%x$(F6oEvq&7&lFtol41u_U(xYRBcoE8KbRwl0!=e}ltFnZQnhA_P>{vC*$yDgZ zPNm4O6itbKT-yN791wlj=+;cSPy=}=CR1R3!gz!w@Xdlx9!p3OzkUNVI26ath*Bsd z;*AJRrLg;2#5!Q+8Lsx~o5rTI~A?`MG6{S-ZaNXZj};Tr_xTTIqW zc^1{TKXi0%IXW|!vyNWX(W{XAtH$;WjOFwFO5>tTt*02$y+QBF~&W{n&L00+h_)*(N+60MWYWuN>$6TpVPN$C(%D35x?RE zjgsy=po{SZh)Y;O<~V(m{=xP#)+Zv#caEW0I#(W9?Ewn# zvc7q}=Anbza&TFPS9N$5hxe=2wvTNe*)j)zX}@D%Gp-rG(gAol>ljfTBZ^~WyRl{M z@beAvQx9E%Emz=+aMm@dx<<3?n97bR?AZ4k;VjCtSm|#>B@d*&I)+~-= zg13!`cbSN{vv?Vk5_E_^#!;+7;F<}sA}i( zMx1Iw^)AKLuR0Fo%{Y!_;>OhaxL(JGXQZZBo3PkH^m)fq?mH|VhlfTdC2<)COz;Ma z4@=??aKxCHkEa$zo@Bsh81v#hIbxa#6hqLH^wlnJ2)qq627ibl;y06;9ekKKu`1RF zPDz3IMYKljpCoS+aH1X(v1?DW!~PRuQlI|NcNf`HSXU$aN7oO@#v*DXtNTJCu_)k& z2%mZ(;>5!WX5q66*vvI!zg9UTl2_@I#JfU3PCq1A zKPVrZKUiMYkL@Wj0~r|mr5}JC$r~t&%AuMS^2;IX3i;(w?F#wjP@_`3bErWn-mteQ zw}M=icMkO`-*@MbQ>nhU(LSa6&LN*tedieq1^Vs(1!=NTrfr5(ig%8&t^^dDH*-nt zI-0c|%`(SS=9oh6CopPDV;(V-sZ4UVrq#W9nzHWy#$c#1eT#tPk-=!n8=xH4ky#66 z$}!DK@h&vs-k7-aR@SyJ%k-*DuR`u8+vbKcYZCf?{!OUKx$eJx>cdlt_povlRM0WC zaZEuD=&s9i$M$jUN43hHQ(suJtz&8{WHdvDvvoaq`>hY(QaX=+-kEJatu~*A#f6L( z*ZSP;#D@u`%b#_gRGlYb{UN#8qo8_ty5Z@}v9&AK?b?Qwnp{&0q~}`Ob*|RtRr(gY z5#6|cC%P#p?T54Nht>AOIq$xV_Y>c}F2#F1>piY|kLNgFhW^BQ&!})mv)oaYJDPKO zHyZA^Hk$#lvH)7H{#;u(Owk*gmz1`FY})^kwx94w}sP&`Mno+GN~NWR|UJO=y8dF&fx zu^#^xlNDp$8D%KI(r44PH@+b`-##aw===BCmcdSRzq5Yu2za(zhU(FS`uZWS;eP-! CVh^7H literal 0 HcmV?d00001 diff --git a/datastore/providers/__pycache__/pinecone_datastore.cpython-310.pyc b/datastore/providers/__pycache__/pinecone_datastore.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95de97243da54fc14aa060e64877b544c1126c1b GIT binary patch literal 6756 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 UtMc=#TCUp24gWRUvFGhS0bmu{h5!Hn literal 0 HcmV?d00001 diff --git a/datastore/providers/analyticdb_datastore.py b/datastore/providers/analyticdb_datastore.py new file mode 100644 index 000000000..ba206f2e1 --- /dev/null +++ b/datastore/providers/analyticdb_datastore.py @@ -0,0 +1,312 @@ +import os +import asyncio +from typing import Dict, List, Optional, Tuple, Any +from datetime import datetime +from loguru import logger + +from psycopg2cffi import compat + +compat.register() +import psycopg2 +from psycopg2.extras import DictCursor +from psycopg2.pool import SimpleConnectionPool + +from services.date import to_unix_timestamp +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + DocumentChunkWithScore, +) + +PG_CONFIG = { + "collection": os.environ.get("PG_COLLECTION", "document_chunks"), + "database": os.environ.get("PG_DATABASE", "postgres"), + "user": os.environ.get("PG_USER", "user"), + "password": os.environ.get("PG_PASSWORD", "password"), + "host": os.environ.get("PG_HOST", "localhost"), + "port": int(os.environ.get("PG_PORT", "5432")), +} +OUTPUT_DIM = 1536 + + +class AnalyticDBDataStore(DataStore): + def __init__(self, config: Dict[str, str] = PG_CONFIG): + self.collection_name = config["collection"] + self.user = config["user"] + self.password = config["password"] + self.database = config["database"] + self.host = config["host"] + self.port = config["port"] + + self.connection_pool = SimpleConnectionPool( + minconn=1, + maxconn=100, + dbname=self.database, + user=self.user, + password=self.password, + host=self.host, + port=self.port, + ) + + self._initialize_db() + + def _initialize_db(self): + conn = self.connection_pool.getconn() + try: + with conn.cursor() as cur: + self._create_table(cur) + self._create_embedding_index(cur) + conn.commit() + finally: + self.connection_pool.putconn(conn) + + def _create_table(self, cur: psycopg2.extensions.cursor): + cur.execute( + f""" + CREATE TABLE IF NOT EXISTS {self.collection_name} ( + id TEXT PRIMARY KEY DEFAULT uuid_generate_v4()::TEXT, + source TEXT, + source_id TEXT, + content TEXT, + document_id TEXT, + author TEXT, + url TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + embedding real[] + ); + """ + ) + + def _create_embedding_index(self, cur: psycopg2.extensions.cursor): + cur.execute( + f""" + SELECT * FROM pg_indexes WHERE tablename='{self.collection_name}'; + """ + ) + index_exists = any( + index[2] == f"{self.collection_name}_embedding_idx" + for index in cur.fetchall() + ) + if not index_exists: + cur.execute( + f""" + CREATE INDEX {self.collection_name}_embedding_idx + ON {self.collection_name} + USING ann(embedding) + WITH ( + distancemeasure=L2, + dim=OUTPUT_DIM, + pq_segments=64, + hnsw_m=100, + pq_centers=2048 + ); + """ + ) + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a dict of document_ids to list of document chunks and inserts them into the database. + Return a list of document ids. + """ + loop = asyncio.get_event_loop() + tasks = [ + loop.run_in_executor(None, self._upsert_chunk, chunk) + for document_chunks in chunks.values() + for chunk in document_chunks + ] + await asyncio.gather(*tasks) + + return list(chunks.keys()) + + def _upsert_chunk(self, chunk: DocumentChunk): + created_at = ( + datetime.fromtimestamp(to_unix_timestamp(chunk.metadata.created_at)) + if chunk.metadata.created_at + else None + ) + data = ( + chunk.id, + chunk.text, + chunk.embedding, + chunk.metadata.document_id, + chunk.metadata.source, + chunk.metadata.source_id, + chunk.metadata.url, + chunk.metadata.author, + created_at, + ) + + conn = self.connection_pool.getconn() + try: + with conn.cursor() as cur: + # Construct the SQL query and data + query = f""" + INSERT INTO {self.collection_name} (id, content, embedding, document_id, source, source_id, url, author, created_at) + VALUES (%s::text, %s::text, %s::real[], %s::text, %s::text, %s::text, %s::text, %s::text, %s::timestamp with time zone) + ON CONFLICT (id) DO UPDATE SET + content = EXCLUDED.content, + embedding = EXCLUDED.embedding, + document_id = EXCLUDED.document_id, + source = EXCLUDED.source, + source_id = EXCLUDED.source_id, + url = EXCLUDED.url, + author = EXCLUDED.author, + created_at = EXCLUDED.created_at; + """ + + # Execute the query + cur.execute(query, data) + + # Commit the transaction + conn.commit() + finally: + self.connection_pool.putconn(conn) + + async def _query(self, queries: List[QueryWithEmbedding]) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + query_results: List[QueryResult] = [] + + def generate_query(query: QueryWithEmbedding) -> Tuple[str, List[Any]]: + embedding = "[" + ", ".join(str(x) for x in query.embedding) + "]" + q = f""" + SELECT + id, + content, + source, + source_id, + document_id, + url, + created_at, + author, + embedding, + l2_distance(embedding,array{embedding}::real[]) AS similarity + FROM + {self.collection_name} + """ + where_clause, params = generate_where_clause(query.filter) + q += where_clause + q += f"ORDER BY embedding <-> array{embedding}::real[] LIMIT {query.top_k};" + return q, params + + def generate_where_clause( + query_filter: Optional[DocumentMetadataFilter], + ) -> Tuple[str, List[Any]]: + if query_filter is None: + return "", [] + + conditions = [ + ("document_id=%s", query_filter.document_id), + ("source_id=%s", query_filter.source_id), + ("source LIKE %s", query_filter.source), + ("author LIKE %s", query_filter.author), + ("created_at >= %s", query_filter.start_date), + ("created_at <= %s", query_filter.end_date), + ] + + where_clause = "WHERE " + " AND ".join( + [cond[0] for cond in conditions if cond[1] is not None] + ) + + values = [cond[1] for cond in conditions if cond[1] is not None] + + return where_clause, values + + def fetch_data(cur, q: str, params: List[Any]): + cur.execute(q, params) + return cur.fetchall() + + def create_results(data): + results = [] + for row in data: + document_chunk = DocumentChunkWithScore( + id=row["id"], + text=row["content"], + score=float(row["similarity"]), + metadata=DocumentChunkMetadata( + source=row["source"], + source_id=row["source_id"], + document_id=row["document_id"], + url=row["url"], + created_at=str(row["created_at"]), + author=row["author"], + ), + ) + results.append(document_chunk) + return results + + conn = self.connection_pool.getconn() + try: + for query in queries: + try: + cur = conn.cursor(cursor_factory=DictCursor) + for query in queries: + q, params = generate_query(query) + data = fetch_data(cur, q, params) + results = create_results(data) + query_results.append( + QueryResult(query=query.query, results=results) + ) + except Exception as e: + logger.error(e) + query_results.append(QueryResult(query=query.query, results=[])) + return query_results + finally: + self.connection_pool.putconn(conn) + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + async def execute_delete(query: str, params: Optional[List] = None) -> bool: + conn = self.connection_pool.getconn() + try: + with conn.cursor() as cur: + if params: + cur.execute(query, params) + else: + cur.execute(query) + self.conn.commit() + return True + except Exception as e: + logger.error(e) + return False + finally: + self.connection_pool.putconn(conn) + + if delete_all: + query = f"DELETE FROM {self.collection_name} WHERE document_id LIKE %s;" + return await execute_delete(query, ["%"]) + elif ids: + query = f"DELETE FROM {self.collection_name} WHERE document_id IN ({','.join(['%s'] * len(ids))});" + return await execute_delete(query, ids) + elif filter is not None: + query, params = self._generate_delete_query(filter) + return await execute_delete(query, params) + else: + return True + + def _generate_delete_query( + self, filter: DocumentMetadataFilter + ) -> Tuple[str, List]: + conditions = [ + (filter.document_id, "document_id = %s"), + (filter.source, "source = %s"), + (filter.source_id, "source_id = %s"), + (filter.author, "author = %s"), + (filter.start_date, "created_at >= %s"), + (filter.end_date, "created_at <= %s"), + ] + + where_conditions = [f for value, f in conditions if value] + where_values = [value for value, _ in conditions if value] + + query = f"DELETE FROM {self.collection_name} WHERE {' AND '.join(where_conditions)};" + return query, where_values diff --git a/datastore/providers/azuresearch_datastore.py b/datastore/providers/azuresearch_datastore.py new file mode 100644 index 000000000..3852258e3 --- /dev/null +++ b/datastore/providers/azuresearch_datastore.py @@ -0,0 +1,260 @@ +import asyncio +import os +import re +import time +import base64 +from typing import Dict, List, Optional, Union +from datastore.datastore import DataStore +from models.models import DocumentChunk, DocumentChunkMetadata, DocumentChunkWithScore, DocumentMetadataFilter, Query, QueryResult, QueryWithEmbedding +from loguru import logger +from azure.search.documents.aio import SearchClient +from azure.search.documents.models import Vector, QueryType +from azure.search.documents.indexes import SearchIndexClient +from azure.search.documents.indexes.models import * +from azure.core.credentials import AzureKeyCredential +from azure.identity import DefaultAzureCredential as DefaultAzureCredentialSync +from azure.identity.aio import DefaultAzureCredential + +AZURESEARCH_SERVICE = os.environ.get("AZURESEARCH_SERVICE") +AZURESEARCH_INDEX = os.environ.get("AZURESEARCH_INDEX") +AZURESEARCH_API_KEY = os.environ.get("AZURESEARCH_API_KEY") +AZURESEARCH_SEMANTIC_CONFIG = os.environ.get("AZURESEARCH_SEMANTIC_CONFIG") +AZURESEARCH_LANGUAGE = os.environ.get("AZURESEARCH_LANGUAGE", "en-us") +AZURESEARCH_DISABLE_HYBRID = os.environ.get("AZURESEARCH_DISABLE_HYBRID") +AZURESEARCH_DIMENSIONS = os.environ.get("AZURESEARCH_DIMENSIONS", 1536) # Default to OpenAI's ada-002 embedding model vector size +assert AZURESEARCH_SERVICE is not None +assert AZURESEARCH_INDEX is not None + +# Allow overriding field names for Azure Search +FIELDS_ID = os.environ.get("AZURESEARCH_FIELDS_ID", "id") +FIELDS_TEXT = os.environ.get("AZURESEARCH_FIELDS_TEXT", "text") +FIELDS_EMBEDDING = os.environ.get("AZURESEARCH_FIELDS_EMBEDDING", "embedding") +FIELDS_DOCUMENT_ID = os.environ.get("AZURESEARCH_FIELDS_DOCUMENT_ID", "document_id") +FIELDS_SOURCE = os.environ.get("AZURESEARCH_FIELDS_SOURCE", "source") +FIELDS_SOURCE_ID = os.environ.get("AZURESEARCH_FIELDS_SOURCE_ID", "source_id") +FIELDS_URL = os.environ.get("AZURESEARCH_FIELDS_URL", "url") +FIELDS_CREATED_AT = os.environ.get("AZURESEARCH_FIELDS_CREATED_AT", "created_at") +FIELDS_AUTHOR = os.environ.get("AZURESEARCH_FIELDS_AUTHOR", "author") + +MAX_UPLOAD_BATCH_SIZE = 1000 +MAX_DELETE_BATCH_SIZE = 1000 + +class AzureSearchDataStore(DataStore): + def __init__(self): + self.client = SearchClient( + endpoint=f"https://{AZURESEARCH_SERVICE}.search.windows.net", + index_name=AZURESEARCH_INDEX, + credential=AzureSearchDataStore._create_credentials(True), + user_agent="retrievalplugin" + ) + + mgmt_client = SearchIndexClient( + endpoint=f"https://{AZURESEARCH_SERVICE}.search.windows.net", + credential=AzureSearchDataStore._create_credentials(False), + user_agent="retrievalplugin" + ) + if AZURESEARCH_INDEX not in [name for name in mgmt_client.list_index_names()]: + self._create_index(mgmt_client) + else: + logger.info(f"Using existing index {AZURESEARCH_INDEX} in service {AZURESEARCH_SERVICE}") + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + azdocuments: List[Dict] = [] + + async def upload(): + r = await self.client.upload_documents(documents=azdocuments) + count = sum(1 for rr in r if rr.succeeded) + logger.info(f"Upserted {count} chunks out of {len(azdocuments)}") + if count < len(azdocuments): + raise Exception(f"Failed to upload {len(azdocuments) - count} chunks") + + ids = [] + for document_id, document_chunks in chunks.items(): + ids.append(document_id) + for chunk in document_chunks: + azdocuments.append({ + # base64-encode the id string to stay within Azure Search's valid characters for keys + FIELDS_ID: base64.urlsafe_b64encode(bytes(chunk.id, "utf-8")).decode("ascii"), + FIELDS_TEXT: chunk.text, + FIELDS_EMBEDDING: chunk.embedding, + FIELDS_DOCUMENT_ID: document_id, + FIELDS_SOURCE: chunk.metadata.source, + FIELDS_SOURCE_ID: chunk.metadata.source_id, + FIELDS_URL: chunk.metadata.url, + FIELDS_CREATED_AT: chunk.metadata.created_at, + FIELDS_AUTHOR: chunk.metadata.author, + }) + + if len(azdocuments) >= MAX_UPLOAD_BATCH_SIZE: + await upload() + azdocuments = [] + + if len(azdocuments) > 0: + await upload() + + return ids + + async def delete(self, ids: Optional[List[str]] = None, filter: Optional[DocumentMetadataFilter] = None, delete_all: Optional[bool] = None) -> bool: + filter = None if delete_all else self._translate_filter(filter) + if delete_all or filter is not None: + deleted = set() + while True: + search_result = await self.client.search(None, filter=filter, top=MAX_DELETE_BATCH_SIZE, include_total_count=True, select=FIELDS_ID) + if await search_result.get_count() == 0: + break + documents = [{ FIELDS_ID: d[FIELDS_ID] } async for d in search_result if d[FIELDS_ID] not in deleted] + if len(documents) > 0: + logger.info(f"Deleting {len(documents)} chunks " + ("using a filter" if filter is not None else "using delete_all")) + del_result = await self.client.delete_documents(documents=documents) + if not all([rr.succeeded for rr in del_result]): + raise Exception("Failed to delete documents") + deleted.update([d[FIELDS_ID] for d in documents]) + else: + # All repeats, delay a bit to let the index refresh and try again + time.sleep(0.25) + + if ids is not None and len(ids) > 0: + for id in ids: + logger.info(f"Deleting chunks for document id {id}") + await self.delete(filter=DocumentMetadataFilter(document_id=id)) + + return True + + async def _query(self, queries: List[QueryWithEmbedding]) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + return await asyncio.gather(*(self._single_query(query) for query in queries)) + + async def _single_query(self, query: QueryWithEmbedding) -> QueryResult: + """ + Takes in a single query and filters and returns a query result with matching document chunks and scores. + """ + filter = self._translate_filter(query.filter) if query.filter is not None else None + try: + vector_top_k = query.top_k if filter is None else query.top_k * 2 + q = query.query if not AZURESEARCH_DISABLE_HYBRID else None + if AZURESEARCH_SEMANTIC_CONFIG != None and not AZURESEARCH_DISABLE_HYBRID: + # Ensure we're feeding a good number of candidates to the L2 reranker + vector_top_k = max(50, vector_top_k) + r = await self.client.search( + q, + filter=filter, + top=query.top_k, + vector=Vector(value=query.embedding, k=vector_top_k, fields=FIELDS_EMBEDDING), + query_type=QueryType.SEMANTIC, + query_language=AZURESEARCH_LANGUAGE, + semantic_configuration_name=AZURESEARCH_SEMANTIC_CONFIG) + else: + r = await self.client.search( + q, + filter=filter, + top=query.top_k, + vector=Vector(value=query.embedding, k=vector_top_k, fields=FIELDS_EMBEDDING)) + results: List[DocumentChunkWithScore] = [] + async for hit in r: + f = lambda field: hit.get(field) if field != "-" else None + results.append(DocumentChunkWithScore( + id=hit[FIELDS_ID], + text=hit[FIELDS_TEXT], + metadata=DocumentChunkMetadata( + document_id=f(FIELDS_DOCUMENT_ID), + source=f(FIELDS_SOURCE), + source_id=f(FIELDS_SOURCE_ID), + url=f(FIELDS_URL), + created_at=f(FIELDS_CREATED_AT), + author=f(FIELDS_AUTHOR) + ), + score=hit["@search.score"] + )) + + return QueryResult(query=query.query, results=results) + except Exception as e: + raise Exception(f"Error querying the index: {e}") + + @staticmethod + def _translate_filter(filter: DocumentMetadataFilter) -> str: + """ + Translates a DocumentMetadataFilter into an Azure Search filter string + """ + if filter is None: + return None + + escape = lambda s: s.replace("'", "''") + + # regex to validate dates are in OData format + date_re = re.compile(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z") + + filter_list = [] + if filter.document_id is not None: + filter_list.append(f"{FIELDS_DOCUMENT_ID} eq '{escape(filter.document_id)}'") + if filter.source is not None: + filter_list.append(f"{FIELDS_SOURCE} eq '{escape(filter.source)}'") + if filter.source_id is not None: + filter_list.append(f"{FIELDS_SOURCE_ID} eq '{escape(filter.source_id)}'") + if filter.author is not None: + filter_list.append(f"{FIELDS_AUTHOR} eq '{escape(filter.author)}'") + if filter.start_date is not None: + if not date_re.match(filter.start_date): + raise ValueError(f"start_date must be in OData format, got {filter.start_date}") + filter_list.append(f"{FIELDS_CREATED_AT} ge {filter.start_date}") + if filter.end_date is not None: + if not date_re.match(filter.end_date): + raise ValueError(f"end_date must be in OData format, got {filter.end_date}") + filter_list.append(f"{FIELDS_CREATED_AT} le {filter.end_date}") + return " and ".join(filter_list) if len(filter_list) > 0 else None + + def _create_index(self, mgmt_client: SearchIndexClient): + """ + Creates an Azure Cognitive Search index, including a semantic search configuration if a name is specified for it + """ + logger.info( + f"Creating index {AZURESEARCH_INDEX} in service {AZURESEARCH_SERVICE}" + + (f" with semantic search configuration {AZURESEARCH_SEMANTIC_CONFIG}" if AZURESEARCH_SEMANTIC_CONFIG is not None else "") + ) + mgmt_client.create_index( + SearchIndex( + name=AZURESEARCH_INDEX, + fields=[ + SimpleField(name=FIELDS_ID, type=SearchFieldDataType.String, key=True), + SearchableField(name=FIELDS_TEXT, type=SearchFieldDataType.String, analyzer_name="standard.lucene"), + SearchField(name=FIELDS_EMBEDDING, type=SearchFieldDataType.Collection(SearchFieldDataType.Single), + hidden=False, searchable=True, filterable=False, sortable=False, facetable=False, + dimensions=AZURESEARCH_DIMENSIONS, vector_search_configuration="default"), + SimpleField(name=FIELDS_DOCUMENT_ID, type=SearchFieldDataType.String, filterable=True, sortable=True), + SimpleField(name=FIELDS_SOURCE, type=SearchFieldDataType.String, filterable=True, sortable=True), + SimpleField(name=FIELDS_SOURCE_ID, type=SearchFieldDataType.String, filterable=True, sortable=True), + SimpleField(name=FIELDS_URL, type=SearchFieldDataType.String), + SimpleField(name=FIELDS_CREATED_AT, type=SearchFieldDataType.DateTimeOffset, filterable=True, sortable=True), + SimpleField(name=FIELDS_AUTHOR, type=SearchFieldDataType.String, filterable=True, sortable=True) + ], + semantic_settings=None if AZURESEARCH_SEMANTIC_CONFIG is None else SemanticSettings( + configurations=[SemanticConfiguration( + name=AZURESEARCH_SEMANTIC_CONFIG, + prioritized_fields=PrioritizedFields( + title_field=None, prioritized_content_fields=[SemanticField(field_name=FIELDS_TEXT)] + ) + )] + ), + vector_search=VectorSearch( + algorithm_configurations=[ + VectorSearchAlgorithmConfiguration( + name="default", + kind="hnsw", + # Could change to dotproduct for OpenAI's embeddings since they normalize vectors to unit length + hnsw_parameters=HnswParameters(metric="cosine") + ) + ] + ) + ) + ) + + @staticmethod + def _create_credentials(use_async: bool) -> Union[AzureKeyCredential, DefaultAzureCredential, DefaultAzureCredentialSync]: + if AZURESEARCH_API_KEY is None: + logger.info("Using DefaultAzureCredential for Azure Search, make sure local identity or managed identity are set up appropriately") + credential = DefaultAzureCredential() if use_async else DefaultAzureCredentialSync() + else: + logger.info("Using an API key to authenticate with Azure Search") + credential = AzureKeyCredential(AZURESEARCH_API_KEY) + return credential diff --git a/datastore/providers/chroma_datastore.py b/datastore/providers/chroma_datastore.py new file mode 100644 index 000000000..59b802d63 --- /dev/null +++ b/datastore/providers/chroma_datastore.py @@ -0,0 +1,250 @@ +""" +Chroma datastore support for the ChatGPT retrieval plugin. + +Consult the Chroma docs and GitHub repo for more information: +- https://docs.trychroma.com/usage-guide?lang=py +- https://github.com/chroma-core/chroma +- https://www.trychroma.com/ +""" + +import os +from datetime import datetime +from typing import Dict, List, Optional + +import chromadb + +from datastore.datastore import DataStore +from models.models import ( + Document, + DocumentChunk, + DocumentChunkMetadata, + DocumentChunkWithScore, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + Source, +) +from services.chunks import get_document_chunks + +CHROMA_IN_MEMORY = os.environ.get("CHROMA_IN_MEMORY", "True") +CHROMA_PERSISTENCE_DIR = os.environ.get("CHROMA_PERSISTENCE_DIR", "openai") +CHROMA_HOST = os.environ.get("CHROMA_HOST", "http://127.0.0.1") +CHROMA_PORT = os.environ.get("CHROMA_PORT", "8000") +CHROMA_COLLECTION = os.environ.get("CHROMA_COLLECTION", "openaiembeddings") + + +class ChromaDataStore(DataStore): + def __init__( + self, + in_memory: bool = CHROMA_IN_MEMORY, # type: ignore + persistence_dir: Optional[str] = CHROMA_PERSISTENCE_DIR, + collection_name: str = CHROMA_COLLECTION, + host: str = CHROMA_HOST, + port: str = CHROMA_PORT, + client: Optional[chromadb.Client] = None, + ): + if client: + self._client = client + else: + if in_memory: + settings = ( + chromadb.config.Settings( + chroma_db_impl="duckdb+parquet", + persist_directory=persistence_dir, + ) + if persistence_dir + else chromadb.config.Settings() + ) + + self._client = chromadb.Client(settings=settings) + else: + self._client = chromadb.Client( + settings=chromadb.config.Settings( + chroma_api_impl="rest", + chroma_server_host=host, + chroma_server_http_port=port, + ) + ) + self._collection = self._client.get_or_create_collection( + name=collection_name, + embedding_function=None, + ) + + async def upsert( + self, documents: List[Document], chunk_token_size: Optional[int] = None + ) -> List[str]: + """ + Takes in a list of documents and inserts them into the database. If an id already exists, the document is updated. + Return a list of document ids. + """ + + chunks = get_document_chunks(documents, chunk_token_size) + + # Chroma has a true upsert, so we don't need to delete first + return await self._upsert(chunks) + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a list of list of document chunks and inserts them into the database. + Return a list of document ids. + """ + + self._collection.upsert( + ids=[chunk.id for chunk_list in chunks.values() for chunk in chunk_list], + embeddings=[ + chunk.embedding + for chunk_list in chunks.values() + for chunk in chunk_list + ], + documents=[ + chunk.text for chunk_list in chunks.values() for chunk in chunk_list + ], + metadatas=[ + self._process_metadata_for_storage(chunk.metadata) + for chunk_list in chunks.values() + for chunk in chunk_list + ], + ) + return list(chunks.keys()) + + def _where_from_query_filter(self, query_filter: DocumentMetadataFilter) -> Dict: + output = { + k: v + for (k, v) in query_filter.dict().items() + if v is not None and k != "start_date" and k != "end_date" and k != "source" + } + if query_filter.source: + output["source"] = query_filter.source.value + if query_filter.start_date and query_filter.end_date: + output["$and"] = [ + { + "created_at": { + "$gte": int( + datetime.fromisoformat(query_filter.start_date).timestamp() + ) + } + }, + { + "created_at": { + "$lte": int( + datetime.fromisoformat(query_filter.end_date).timestamp() + ) + } + }, + ] + elif query_filter.start_date: + output["created_at"] = { + "$gte": int(datetime.fromisoformat(query_filter.start_date).timestamp()) + } + elif query_filter.end_date: + output["created_at"] = { + "$lte": int(datetime.fromisoformat(query_filter.end_date).timestamp()) + } + + return output + + def _process_metadata_for_storage(self, metadata: DocumentChunkMetadata) -> Dict: + stored_metadata = {} + if metadata.source: + stored_metadata["source"] = metadata.source.value + if metadata.source_id: + stored_metadata["source_id"] = metadata.source_id + if metadata.url: + stored_metadata["url"] = metadata.url + if metadata.created_at: + stored_metadata["created_at"] = int( + datetime.fromisoformat(metadata.created_at).timestamp() + ) + if metadata.author: + stored_metadata["author"] = metadata.author + if metadata.document_id: + stored_metadata["document_id"] = metadata.document_id + + return stored_metadata + + def _process_metadata_from_storage(self, metadata: Dict) -> DocumentChunkMetadata: + return DocumentChunkMetadata( + source=Source(metadata["source"]) if "source" in metadata else None, + source_id=metadata.get("source_id", None), + url=metadata.get("url", None), + created_at=datetime.fromtimestamp(metadata["created_at"]).isoformat() + if "created_at" in metadata + else None, + author=metadata.get("author", None), + document_id=metadata.get("document_id", None), + ) + + async def _query(self, queries: List[QueryWithEmbedding]) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + results = [ + self._collection.query( + query_embeddings=[query.embedding], + include=["documents", "distances", "metadatas"], # embeddings + n_results=min(query.top_k, self._collection.count()), # type: ignore + where=( + self._where_from_query_filter(query.filter) if query.filter else {} + ), + ) + for query in queries + ] + + output = [] + for query, result in zip(queries, results): + inner_results = [] + (ids,) = result["ids"] + # (embeddings,) = result["embeddings"] + (documents,) = result["documents"] + (metadatas,) = result["metadatas"] + (distances,) = result["distances"] + for id_, text, metadata, distance in zip( + ids, + documents, + metadatas, + distances, # embeddings (https://github.com/openai/chatgpt-retrieval-plugin/pull/59#discussion_r1154985153) + ): + inner_results.append( + DocumentChunkWithScore( + id=id_, + text=text, + metadata=self._process_metadata_from_storage(metadata), + # embedding=embedding, + score=distance, + ) + ) + output.append(QueryResult(query=query.query, results=inner_results)) + + return output + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything in the datastore. + Multiple parameters can be used at once. + Returns whether the operation was successful. + """ + if delete_all: + self._collection.delete() + return True + + if ids and len(ids) > 0: + if len(ids) > 1: + where_clause = {"$or": [{"document_id": id_} for id_ in ids]} + else: + (id_,) = ids + where_clause = {"document_id": id_} + + if filter: + where_clause = { + "$and": [self._where_from_query_filter(filter), where_clause] + } + elif filter: + where_clause = self._where_from_query_filter(filter) + + self._collection.delete(where=where_clause) + return True diff --git a/datastore/providers/elasticsearch_datastore.py b/datastore/providers/elasticsearch_datastore.py new file mode 100644 index 000000000..6380735c5 --- /dev/null +++ b/datastore/providers/elasticsearch_datastore.py @@ -0,0 +1,351 @@ +import os +from typing import Dict, List, Any, Optional + +import elasticsearch +from elasticsearch import Elasticsearch, helpers +from loguru import logger + +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentChunkWithScore, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, +) +from services.date import to_unix_timestamp + +ELASTICSEARCH_URL = os.environ.get("ELASTICSEARCH_URL", "http://localhost:9200") +ELASTICSEARCH_CLOUD_ID = os.environ.get("ELASTICSEARCH_CLOUD_ID") +ELASTICSEARCH_USERNAME = os.environ.get("ELASTICSEARCH_USERNAME") +ELASTICSEARCH_PASSWORD = os.environ.get("ELASTICSEARCH_PASSWORD") +ELASTICSEARCH_API_KEY = os.environ.get("ELASTICSEARCH_API_KEY") + +ELASTICSEARCH_INDEX = os.environ.get("ELASTICSEARCH_INDEX") +ELASTICSEARCH_REPLICAS = int(os.environ.get("ELASTICSEARCH_REPLICAS", "1")) +ELASTICSEARCH_SHARDS = int(os.environ.get("ELASTICSEARCH_SHARDS", "1")) + +VECTOR_SIZE = 1536 +UPSERT_BATCH_SIZE = 100 + + +class ElasticsearchDataStore(DataStore): + def __init__( + self, + index_name: Optional[str] = None, + vector_size: int = VECTOR_SIZE, + similarity: str = "cosine", + replicas: int = ELASTICSEARCH_REPLICAS, + shards: int = ELASTICSEARCH_SHARDS, + recreate_index: bool = True, + ): + """ + Args: + index_name: Name of the index to be used + vector_size: Size of the embedding stored in a collection + similarity: + Any of "cosine" / "l2_norm" / "dot_product". + + """ + assert similarity in [ + "cosine", + "l2_norm", + "dot_product", + ], "Similarity must be one of 'cosine' / 'l2_norm' / 'dot_product'." + assert replicas > 0, "Replicas must be greater than or equal to 0." + assert shards > 0, "Shards must be greater than or equal to 0." + + self.client = connect_to_elasticsearch( + ELASTICSEARCH_URL, + ELASTICSEARCH_CLOUD_ID, + ELASTICSEARCH_API_KEY, + ELASTICSEARCH_USERNAME, + ELASTICSEARCH_PASSWORD, + ) + assert ( + index_name != "" or ELASTICSEARCH_INDEX != "" + ), "Please provide an index name." + self.index_name = index_name or ELASTICSEARCH_INDEX or "" + + replicas = replicas or ELASTICSEARCH_REPLICAS + shards = shards or ELASTICSEARCH_SHARDS + + # Set up the collection so the documents might be inserted or queried + self._set_up_index(vector_size, similarity, replicas, shards, recreate_index) + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a list of document chunks and inserts them into the database. + Return a list of document ids. + """ + actions = [] + for _, chunkList in chunks.items(): + for chunk in chunkList: + actions = ( + actions + + self._convert_document_chunk_to_es_document_operation(chunk) + ) + + self.client.bulk(operations=actions, index=self.index_name) + return list(chunks.keys()) + + async def _query( + self, + queries: List[QueryWithEmbedding], + ) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + searches = self._convert_queries_to_msearch_query(queries) + results = self.client.msearch(searches=searches) + return [ + QueryResult( + query=query.query, + results=[ + self._convert_hit_to_document_chunk_with_score(hit) + for hit in result["hits"]["hits"] + ], + ) + for query, result in zip(queries, results["responses"]) + ] + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything in the datastore. + Returns whether the operation was successful. + """ + + # Delete all vectors from the index if delete_all is True + if delete_all: + try: + logger.info(f"Deleting all vectors from index") + self.client.delete_by_query( + index=self.index_name, query={"match_all": {}} + ) + logger.info(f"Deleted all vectors successfully") + return True + except Exception as e: + logger.error(f"Error deleting all vectors: {e}") + raise e + + # Convert the metadata filter object to a dict with elasticsearch filter expressions + es_filters = self._get_es_filters(filter) + # Delete vectors that match the filter from the index if the filter is not empty + if es_filters != {}: + try: + logger.info(f"Deleting vectors with filter {es_filters}") + self.client.delete_by_query(index=self.index_name, query=es_filters) + logger.info(f"Deleted vectors with filter successfully") + except Exception as e: + logger.error(f"Error deleting vectors with filter: {e}") + raise e + + if ids: + try: + documents_to_delete = [doc_id for doc_id in ids] + logger.info(f"Deleting {len(documents_to_delete)} documents") + res = self.client.delete_by_query( + index=self.index_name, + query={"terms": {"metadata.document_id": documents_to_delete}}, + ) + logger.info(f"Deleted documents successfully") + except Exception as e: + logger.error(f"Error deleting documents: {e}") + raise e + + return True + + def _get_es_filters( + self, filter: Optional[DocumentMetadataFilter] = None + ) -> Dict[str, Any]: + if filter is None: + return {} + + es_filters = { + "bool": { + "must": [], + } + } + + # For each field in the MetadataFilter, check if it has a value and add the corresponding pinecone filter expression + # For start_date and end_date, uses the range query - gte and lte operators respectively + # For other fields, uses the term query + for field, value in filter.dict().items(): + if value is not None: + if field == "start_date": + es_filters["bool"]["must"].append( + {"range": {"created_at": {"gte": to_unix_timestamp(value)}}} + ) + elif field == "end_date": + es_filters["bool"]["must"].append( + {"range": {"created_at": {"lte": to_unix_timestamp(value)}}} + ) + else: + es_filters["bool"]["must"].append( + {"term": {f"metadata.{field}": value}} + ) + + return es_filters + + def _convert_document_chunk_to_es_document_operation( + self, document_chunk: DocumentChunk + ) -> List[Dict]: + created_at = ( + to_unix_timestamp(document_chunk.metadata.created_at) + if document_chunk.metadata.created_at is not None + else None + ) + + action_and_metadata = { + "index": { + "_index": self.index_name, + "_id": document_chunk.id, + } + } + + source = { + "id": document_chunk.id, + "text": document_chunk.text, + "metadata": document_chunk.metadata.dict(), + "created_at": created_at, + "embedding": document_chunk.embedding, + } + + return [action_and_metadata, source] + + def _convert_queries_to_msearch_query(self, queries: List[QueryWithEmbedding]): + searches = [] + + for query in queries: + searches.append({"index": self.index_name}) + searches.append( + { + "_source": True, + "knn": { + "field": "embedding", + "query_vector": query.embedding, + "k": query.top_k, + "num_candidates": query.top_k, + }, + "size": query.top_k, + } + ) + + return searches + + def _convert_hit_to_document_chunk_with_score(self, hit) -> DocumentChunkWithScore: + return DocumentChunkWithScore( + id=hit["_id"], + text=hit["_source"]["text"], # type: ignore + metadata=hit["_source"]["metadata"], # type: ignore + embedding=hit["_source"]["embedding"], # type: ignore + score=hit["_score"], + ) + + def _set_up_index( + self, + vector_size: int, + similarity: str, + replicas: int, + shards: int, + recreate_index: bool, + ) -> None: + if recreate_index: + self._recreate_index(similarity, vector_size, replicas, shards) + + try: + index_mapping = self.client.indices.get_mapping(index=self.index_name) + current_similarity = index_mapping[self.index_name]["mappings"]["properties"]["embedding"]["similarity"] # type: ignore + current_vector_size = index_mapping[self.index_name]["mappings"]["properties"]["embedding"]["dims"] # type: ignore + + if current_similarity != similarity: + raise ValueError( + f"Collection '{self.index_name}' already exists in Elasticsearch, " + f"but it is configured with a similarity '{current_similarity}'. " + f"If you want to use that collection, but with a different " + f"similarity, please set `recreate_index=True` argument." + ) + + if current_vector_size != vector_size: + raise ValueError( + f"Collection '{self.index_name}' already exists in Elasticsearch, " + f"but it is configured with a vector size '{current_vector_size}'. " + f"If you want to use that collection, but with a different " + f"vector size, please set `recreate_index=True` argument." + ) + except elasticsearch.exceptions.NotFoundError: + self._recreate_index(similarity, vector_size, replicas, shards) + + def _recreate_index( + self, similarity: str, vector_size: int, replicas: int, shards: int + ) -> None: + settings = { + "index": { + "number_of_shards": shards, + "number_of_replicas": replicas, + "refresh_interval": "1s", + } + } + mappings = { + "properties": { + "embedding": { + "type": "dense_vector", + "dims": vector_size, + "index": True, + "similarity": similarity, + } + } + } + + self.client.indices.delete( + index=self.index_name, ignore_unavailable=True, allow_no_indices=True + ) + self.client.indices.create( + index=self.index_name, mappings=mappings, settings=settings + ) + + +def connect_to_elasticsearch( + elasticsearch_url=None, cloud_id=None, api_key=None, username=None, password=None +): + # Check if both elasticsearch_url and cloud_id are defined + if elasticsearch_url and cloud_id: + raise ValueError( + "Both elasticsearch_url and cloud_id are defined. Please provide only one." + ) + + # Initialize connection parameters dictionary + connection_params = {} + + # Define the connection based on the provided parameters + if elasticsearch_url: + connection_params["hosts"] = [elasticsearch_url] + elif cloud_id: + connection_params["cloud_id"] = cloud_id + else: + raise ValueError("Please provide either elasticsearch_url or cloud_id.") + + # Add authentication details based on the provided parameters + if api_key: + connection_params["api_key"] = api_key + elif username and password: + connection_params["basic_auth"] = (username, password) + else: + logger.warning( + "No authentication details provided. Please consider using an api_key or username and password to secure your connection." + ) + + # Establish the Elasticsearch client connection + es_client = Elasticsearch(**connection_params) + try: + es_client.info() + except Exception as e: + logger.error(f"Error connecting to Elasticsearch: {e}") + raise e + + return es_client diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py new file mode 100644 index 000000000..47590f070 --- /dev/null +++ b/datastore/providers/kdbai_datastore.py @@ -0,0 +1,421 @@ +import json +import os +import asyncio +import pandas as pd +import numpy as np + + +from loguru import logger +from typing import Any, Dict, List, Optional +from uuid import uuid4 + +from services.date import to_unix_timestamp +from datastore.datastore import DataStore + +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + Source, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + DocumentChunkWithScore, +) + +try: + ## New for kdbai_client + import kdbai_client as kdbai + print('KDBAI-CLIENT version: ' + kdbai.__version__) + ## + +except ImportError: + raise ValueError( + "Could not import kdbai python package. " + "Please add it to the dependencies." + ) + +try: + import pykx as kx + print('PyKX version: ' + kx.__version__) + +except ImportError: + raise ValueError( + "Could not import pykx python package. " + "Please add it to the dependencies." + ) + + +SCHEMA = { + { + "name": "chunk_id", + "dataType": ["string"], + "description": "The chunk id", + }, + { + "name": "document_id", + "dataType": ["string"], + "description": "The document id", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The chunk's text", + }, + { + "name": "source", + "dataType": ["string"], + "description": "The source of the data", + }, + { + "name": "source_id", + "dataType": ["string"], + "description": "The source id", + }, + { + "name": "url", + "dataType": ["string"], + "description": "The source url", + }, + { + "name": "created_at", + "dataType": ["date"], + "description": "Creation date of document", + }, + { + "name": "author", + "dataType": ["string"], + "description": "Document author", + }, +} + + +# DEFAULT_EMBEDDING_MODEL = 'text-embedding-ada-002' + +# The name of the table +KDBAI_COLLECTION = os.environ.get("KDBAI_COLLECTION", "openaiEmbeddings") + +# Directory where conversation memory is saved (?) +KDBAI_PERSISTENCE_DIR = os.environ.get("KDBAI_PERSISTENCE_DIR", "openai") + +# Not needed? +KDBAI_INDEX_PARAMS = os.environ.get("KDBAI_INDEX_PARAMS", None) # {"efConstruction": 8, "efSearch": 8, "M": 32} + +# Not needed? +KDBAI_SEARCH_PARAMS = os.environ.get("KDBAI_SEARCH_PARAMS") + +# Algorithm/index for vector similarity search +DEFAULT_ALGORITHM = os.environ.get("DEFAULT_ALGORITHM") + +# HNSW's Default Parameters +DEFAULT_EFCONSTRUCTION = 8 +DEFAULT_M = 32 + +DEFAULT_DIM = 1536 +UPSERT_BATCH_SIZE = 100 +KDBAI_VECTOR_COL_NAME = "vecs" + + +table = pd.DataFrame({'text': pd.Series(dtype='str'), + 'document_id': pd.Series(dtype='str'), + 'source_id': pd.Series(dtype='str'), + 'id': pd.Series(dtype='str'), + 'source': pd.Series(dtype='str'), + 'url': pd.Series(dtype='str'), + 'created_at': pd.Series(dtype='str'), + 'body': pd.Series(dtype='str'), + 'vecs': pd.Series(dtype='float32')}) + + +class KDBAIDataStore(DataStore): + + def __init__( + self, + # name of the collection of embeddings + index_name: str = KDBAI_COLLECTION, + + # where conversation memory is saved + # persist_directory: Optional[str] = KDBAI_PERSISTENCE_DIR, + + # manually input the index params (algorithm, metric, dimensions etc) + # options: Optional[str] = KDBAI_INDEX_PARAMS + ) -> None: + + self._index_name = index_name + + # self._persist_directory = persist_directory + # self._options = options + + # self.search_params = KDBAI_SEARCH_PARAMS or None + + try: + + # NEW KDBAI-CLIENT + + # create a new session + print('Creating kdbai Session...') + session = kdbai.Session(host='localhost', port=8082, protocol='http') + print("Tables in current session:") + print(session.list()) + + # load the table configuration for the kdbai vector database (see schema from milvus) + # schema = json.loads(""" + # {"type":"splayed", + # "columns":[ + # {"name": "time", "type": "timespan"}, + # {"name": "sym", "type": "symbol"}, + # {"name": "id", "type": "symbol"}, + # {"name": "tag", "type": "symbol", "attrMem": "grouped"}, + # {"name": "text", "type": "string"}, + # {"name": "embeddings", "type": "reals", + # "vectorIndex": {"type": "flat", "metric": "L2", "dims": 1536}}] + # }""") + + ## ^^ USE SCHEMA INSTEAD + + # create a vector database table using the schema + print('Accessing \'documents\' table:') + self._table = session.table('documents') + print(self._table.query()) + + except Exception as e: + logger.error(f"Error in creating table: {e}") + raise e + + return None + + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """Upsert chunks into the datastore. + + Args: + chunks (Dict[str, List[DocumentChunk]]): A list of DocumentChunks to insert + + Raises: + e: Error in upserting data. + + Returns: + List[str]: The document_id's that were inserted. + """ + + # Initialize a list of ids to return + try: + global table + doc_ids: List[str] = [] + + # Initialize a list of vectors to upsert + vecs = [] + # Loop through the dict items + for doc_id, chunk_list in chunks.items(): + # Append the id to the ids list + + print(f"doc_id: {doc_id}") + print(f"chunk_list: {chunk_list}") + + doc_ids.append(doc_id) + logger.info(f"Upserting document_id: {doc_id}") + + for chunk in chunk_list: + + print(f"chunk: {chunk}") + + # Create a vector tuple of (id, embedding, metadata) + # Convert the metadata object to a dict with unix timestamps for dates + self._metadata = self._kdbai_metadata(chunk.metadata) # chunk.metadata comes from retrieval app + + # Add the text and document id to the metadata DICT + self._metadata["text"] = chunk.text + self._metadata["document_id"] = doc_id + self._metadata["chunk_id"] = chunk.id + + vec = (chunk.embedding, self._metadata) + vecs.append(vec) + + # Slice up our insert data into batches + batches = [ + vecs[i : i + UPSERT_BATCH_SIZE] + for i in range(0, len(vecs), UPSERT_BATCH_SIZE) + ] + + for batch in batches: + + # generates an embedding vector of length batch + embeddings = np.array([t[0] for t in batch]) + + df = pd.DataFrame(dict(vecs=list(embeddings))) + new_meta_df = pd.DataFrame([t[1] for t in batch]) + + for col in new_meta_df.columns: + df[col]=new_meta_df[col] + + try: + logger.info(f"Upserting batch of size {len(batch[0])}") + + # call insert() function from kdbai.Index() instance + #self._index.insert(embeddings) + + # NEW KDBAI-CLIENT requires pd.DataFrame input + # INSERT EMBEDDINGS + METADATA AT SAME TIME + + # make dataframe with schema + + + self._table.insert(pd.DataFrame(embeddings).T) + + logger.info(f"Upserted batch successfully") + table = table.append(df) + + except Exception as e: + logger.error(f"Failed to insert batch records, error: {e}") + raise e + + return doc_ids + # try: + # df = kx.q('{([] time:0Nn; sym:`; id: `$string x?0Ng; tag: x?`3; text: {rand[256]?" "} each til x; embeddings: (x;1536)#(x*1536)?1e)}', 10).pd() + # self._table.insert(df) + # print("inserted to the table!") + # self._table.query() + + except Exception as e: + logger.error("Insert to collection failed, error: {}".format(e)) + return [] + + + def _kdbai_metadata( + self, metadata: Optional[DocumentChunkMetadata] = None + ) -> Dict[str, Any]: + if metadata is None: + return {} + + kdbai_metadata = {} + + for key, value in metadata.dict().items(): + if value is not None: + if key in ["created_at"]: + kdbai_metadata["created_at"] = to_unix_timestamp(value) + else: + kdbai_metadata[key] = value + + return kdbai_metadata + + + ## QUERY vs SEARCH + async def _query( + self, + queries: List[QueryWithEmbedding], # a list of embedded query vectors + ) -> List[QueryResult]: + """Query + + Search the embedding and its filter in the collection. + + Args: + queries (List[QueryWithEmbedding]): The list of searches to perform. + + Returns: + List[QueryResult]: Results for each search. + """ + + # handle each query vector at a time + async def _single_query(query: QueryWithEmbedding) -> QueryResult: + + try: + + # if there are no filters, just return the n nearest neighbours and their ids + if query.filter is None: + + # calls search() function from kdbai.Index() + # Input: a batch of query vectors and a number of nearest records to search + # Output: a tuple with 2D Numpy arrays containing the distances and IDs of nearest vectors + #dist, ids = self._index.search(np.array([query.embedding]).astype('float32'), k=query.top_k) + + # NEW KDBAI-CLIENT + search_results = self._table.search(dict(vectors=np.array([query.embedding]).astype('float32'), n=query.top_k)) + dist = search_results["__nn_distance"] + ids = search_results["id"] + + + # HANDLE CASES WHERE WE WANT TO FILTER THE RESULTS (see bottom of file for params here) + + # else: + # whereDict = query.filter.dict() + + # if len(whereDict.keys()) > 1: + # raise ValueError("Only 1 filter is allowed currently.") + + # filterStr = "\""+(''.join([str(list(x)[0]) for x in [whereDict.keys(), whereDict.values()]]))+"\"" + # responses = self._index.filtered_search(np.array([query.embedding]).astype('float32'), filterStr, verbose=1, options=dict(neighbors=query.top_k)).pd() + + except Exception as e: + logger.error(f"Error querying index: {e}") + raise e + + global table + query_results: List[DocumentChunkWithScore] = [] + + # iterate through the query results + for dist, id in zip(dist[0],ids[0]): + + indices = id + score = dist + text = table.loc[table.index == id]["text"].values[0] + + metadata = table.drop(['vecs','text'],axis=1).loc[table.index == id].squeeze().to_dict() + + # If the source is not a valid Source in the Source enum, set it to None + if ( + metadata + and "source" in metadata + and metadata["source"] not in Source.__members__ + ): + metadata["source"] = None + + # Create a document chunk with score object with the result data + result = DocumentChunkWithScore( + id=indices, + score=score, + text=text, + metadata=metadata, + ) + query_results.append(result) + + return QueryResult(query=query.query, results=query_results) + + + # iterate through each query and gather results + results: List[QueryResult] = await asyncio.gather( + *[_single_query(query) for query in queries] + ) + + return results + + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + + # If deleting all, drop collection + try: + global table + if delete_all: + + #self._index.drop() + + # NEW KDBAI-CLIENT + self._table.drop() + + table = table.head(0) + else: + logger.error("Functionality is not implemented yet") + + return True + + except Exception as e: + logger.error("Failed to insert records, error: {}".format(e)) + return [] + + +## query = dict(labels=dict(region, assetClass), +# startTS, endTS, inputTZ, outputTZ, +# filter, groupBy, agg, temporality, sortCols) \ No newline at end of file diff --git a/datastore/providers/llama_datastore.py b/datastore/providers/llama_datastore.py new file mode 100644 index 000000000..9a0713662 --- /dev/null +++ b/datastore/providers/llama_datastore.py @@ -0,0 +1,181 @@ +import json +import os +from typing import Dict, List, Optional, Type +from loguru import logger +from datastore.datastore import DataStore +from models.models import DocumentChunk, DocumentChunkMetadata, DocumentChunkWithScore, DocumentMetadataFilter, Query, QueryResult, QueryWithEmbedding + +from llama_index.indices.base import BaseGPTIndex +from llama_index.indices.vector_store.base import GPTVectorStoreIndex +from llama_index.indices.query.schema import QueryBundle +from llama_index.response.schema import Response +from llama_index.data_structs.node_v2 import Node, DocumentRelationship, NodeWithScore +from llama_index.indices.registry import INDEX_STRUCT_TYPE_TO_INDEX_CLASS +from llama_index.data_structs.struct_type import IndexStructType +from llama_index.indices.response.builder import ResponseMode + +INDEX_STRUCT_TYPE_STR = os.environ.get('LLAMA_INDEX_TYPE', IndexStructType.SIMPLE_DICT.value) +INDEX_JSON_PATH = os.environ.get('LLAMA_INDEX_JSON_PATH', None) +QUERY_KWARGS_JSON_PATH = os.environ.get('LLAMA_QUERY_KWARGS_JSON_PATH', None) +RESPONSE_MODE = os.environ.get('LLAMA_RESPONSE_MODE', ResponseMode.NO_TEXT.value) + +EXTERNAL_VECTOR_STORE_INDEX_STRUCT_TYPES = [ + IndexStructType.DICT, + IndexStructType.WEAVIATE, + IndexStructType.PINECONE, + IndexStructType.QDRANT, + IndexStructType.CHROMA, + IndexStructType.VECTOR_STORE, +] + +def _create_or_load_index( + index_type_str: Optional[str] = None, + index_json_path: Optional[str] = None, + index_type_to_index_cls: Optional[dict[str, Type[BaseGPTIndex]]] = None, +) -> BaseGPTIndex: + """Create or load index from json path.""" + index_json_path = index_json_path or INDEX_JSON_PATH + index_type_to_index_cls = index_type_to_index_cls or INDEX_STRUCT_TYPE_TO_INDEX_CLASS + index_type_str = index_type_str or INDEX_STRUCT_TYPE_STR + index_type = IndexStructType(index_type_str) + + if index_type not in index_type_to_index_cls: + raise ValueError(f'Unknown index type: {index_type}') + + if index_type in EXTERNAL_VECTOR_STORE_INDEX_STRUCT_TYPES: + raise ValueError('Please use vector store directly.') + + index_cls = index_type_to_index_cls[index_type] + if index_json_path is None: + return index_cls(nodes=[]) # Create empty index + else: + return index_cls.load_from_disk(index_json_path) # Load index from disk + +def _create_or_load_query_kwargs(query_kwargs_json_path: Optional[str] = None) -> Optional[dict]: + """Create or load query kwargs from json path.""" + query_kwargs_json_path= query_kwargs_json_path or QUERY_KWARGS_JSON_PATH + query_kargs: Optional[dict] = None + if query_kwargs_json_path is not None: + with open(INDEX_JSON_PATH, 'r') as f: + query_kargs = json.load(f) + return query_kargs + + +def _doc_chunk_to_node(doc_chunk: DocumentChunk, source_doc_id: str) -> Node: + """Convert document chunk to Node""" + return Node( + doc_id=doc_chunk.id, + text=doc_chunk.text, + embedding=doc_chunk.embedding, + extra_info=doc_chunk.metadata.dict(), + relationships={ + DocumentRelationship.SOURCE: source_doc_id + } + ) + +def _query_with_embedding_to_query_bundle(query: QueryWithEmbedding) -> QueryBundle: + return QueryBundle( + query_str = query.query, + embedding=query.embedding, + ) + +def _source_node_to_doc_chunk_with_score(node_with_score: NodeWithScore) -> DocumentChunkWithScore: + node = node_with_score.node + if node.extra_info is not None: + metadata = DocumentChunkMetadata(**node.extra_info) + else: + metadata = DocumentChunkMetadata() + + return DocumentChunkWithScore( + id=node.doc_id, + text=node.text, + score=node_with_score.score if node_with_score.score is not None else 1., + metadata=metadata, + ) + +def _response_to_query_result(response: Response, query: QueryWithEmbedding) -> QueryResult: + results = [_source_node_to_doc_chunk_with_score(node) for node in response.source_nodes] + return QueryResult(query=query.query, results=results,) + +class LlamaDataStore(DataStore): + def __init__(self, index: Optional[BaseGPTIndex] = None, query_kwargs: Optional[dict] = None): + self._index = index or _create_or_load_index() + self._query_kwargs = query_kwargs or _create_or_load_query_kwargs() + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a list of list of document chunks and inserts them into the database. + Return a list of document ids. + """ + doc_ids = [] + for doc_id, doc_chunks in chunks.items(): + logger.debug(f"Upserting {doc_id} with {len(doc_chunks)} chunks") + + nodes = [ + _doc_chunk_to_node(doc_chunk=doc_chunk, source_doc_id=doc_id) + for doc_chunk in doc_chunks + ] + + self._index.insert_nodes(nodes) + doc_ids.append(doc_id) + return doc_ids + + async def _query( + self, + queries: List[QueryWithEmbedding], + ) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and + returns a list of query results with matching document chunks and scores. + """ + query_result_all = [] + for query in queries: + if query.filter is not None: + logger.warning('Filters are not supported yet, ignoring for now.') + + query_bundle = _query_with_embedding_to_query_bundle(query) + + # Setup query kwargs + if self._query_kwargs is not None: + query_kwargs = self._query_kwargs + else: + query_kwargs = {} + # TODO: support top_k for other indices + if isinstance(self._index, GPTVectorStoreIndex): + query_kwargs['similarity_top_k'] = query.top_k + + response = await self._index.aquery(query_bundle, response_mode=RESPONSE_MODE, **query_kwargs) + + query_result = _response_to_query_result(response, query) + query_result_all.append(query_result) + + return query_result_all + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything in the datastore. + Returns whether the operation was successful. + """ + if delete_all: + logger.warning('Delete all not supported yet.') + return False + + if filter is not None: + logger.warning('Filters are not supported yet.') + return False + + if ids is not None: + for id_ in ids: + try: + self._index.delete(id_) + except NotImplementedError: + # NOTE: some indices does not support delete yet. + logger.warning(f'{type(self._index)} does not support delete yet.') + return False + + return True \ No newline at end of file diff --git a/datastore/providers/milvus_datastore.py b/datastore/providers/milvus_datastore.py new file mode 100644 index 000000000..d105cc4e9 --- /dev/null +++ b/datastore/providers/milvus_datastore.py @@ -0,0 +1,560 @@ +import json +import os +import asyncio + +from loguru import logger +from typing import Dict, List, Optional +from pymilvus import ( + Collection, + connections, + utility, + FieldSchema, + DataType, + CollectionSchema, + MilvusException, +) +from uuid import uuid4 + + +from services.date import to_unix_timestamp +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + Source, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + DocumentChunkWithScore, +) + +MILVUS_COLLECTION = os.environ.get("MILVUS_COLLECTION") or "c" + uuid4().hex +MILVUS_HOST = os.environ.get("MILVUS_HOST") or "localhost" +MILVUS_PORT = os.environ.get("MILVUS_PORT") or 19530 +MILVUS_USER = os.environ.get("MILVUS_USER") +MILVUS_PASSWORD = os.environ.get("MILVUS_PASSWORD") +MILVUS_USE_SECURITY = False if MILVUS_PASSWORD is None else True + +MILVUS_INDEX_PARAMS = os.environ.get("MILVUS_INDEX_PARAMS") +MILVUS_SEARCH_PARAMS = os.environ.get("MILVUS_SEARCH_PARAMS") +MILVUS_CONSISTENCY_LEVEL = os.environ.get("MILVUS_CONSISTENCY_LEVEL") + +UPSERT_BATCH_SIZE = 100 +OUTPUT_DIM = 1536 +EMBEDDING_FIELD = "embedding" + + +class Required: + pass + +# The fields names that we are going to be storing within Milvus, the field declaration for schema creation, and the default value +SCHEMA_V1 = [ + ( + "pk", + FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=True), + Required, + ), + ( + EMBEDDING_FIELD, + FieldSchema(name=EMBEDDING_FIELD, dtype=DataType.FLOAT_VECTOR, dim=OUTPUT_DIM), + Required, + ), + ( + "text", + FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=65535), + Required, + ), + ( + "document_id", + FieldSchema(name="document_id", dtype=DataType.VARCHAR, max_length=65535), + "", + ), + ( + "source_id", + FieldSchema(name="source_id", dtype=DataType.VARCHAR, max_length=65535), + "", + ), + ( + "id", + FieldSchema( + name="id", + dtype=DataType.VARCHAR, + max_length=65535, + ), + "", + ), + ( + "source", + FieldSchema(name="source", dtype=DataType.VARCHAR, max_length=65535), + "", + ), + ("url", FieldSchema(name="url", dtype=DataType.VARCHAR, max_length=65535), ""), + ("created_at", FieldSchema(name="created_at", dtype=DataType.INT64), -1), + ( + "author", + FieldSchema(name="author", dtype=DataType.VARCHAR, max_length=65535), + "", + ), +] + +# V2 schema, remomve the "pk" field +SCHEMA_V2 = SCHEMA_V1[1:] +SCHEMA_V2[4][1].is_primary = True + + +class MilvusDataStore(DataStore): + def __init__( + self, + create_new: Optional[bool] = False, + consistency_level: str = "Bounded", + ): + """Create a Milvus DataStore. + + The Milvus Datastore allows for storing your indexes and metadata within a Milvus instance. + + Args: + create_new (Optional[bool], optional): Whether to overwrite if collection already exists. Defaults to True. + consistency_level(str, optional): Specify the collection consistency level. + Defaults to "Bounded" for search performance. + Set to "Strong" in test cases for result validation. + """ + # Overwrite the default consistency level by MILVUS_CONSISTENCY_LEVEL + self._consistency_level = MILVUS_CONSISTENCY_LEVEL or consistency_level + self._create_connection() + + self._create_collection(MILVUS_COLLECTION, create_new) # type: ignore + self._create_index() + + def _get_schema(self): + return SCHEMA_V1 if self._schema_ver == "V1" else SCHEMA_V2 + + def _create_connection(self): + try: + self.alias = "" + # Check if the connection already exists + for x in connections.list_connections(): + addr = connections.get_connection_addr(x[0]) + if x[1] and ('address' in addr) and (addr['address'] == "{}:{}".format(MILVUS_HOST, MILVUS_PORT)): + self.alias = x[0] + logger.info("Reuse connection to Milvus server '{}:{}' with alias '{:s}'" + .format(MILVUS_HOST, MILVUS_PORT, self.alias)) + break + + # Connect to the Milvus instance using the passed in Environment variables + if len(self.alias) == 0: + self.alias = uuid4().hex + connections.connect( + alias=self.alias, + host=MILVUS_HOST, + port=MILVUS_PORT, + user=MILVUS_USER, # type: ignore + password=MILVUS_PASSWORD, # type: ignore + secure=MILVUS_USE_SECURITY, + ) + logger.info("Create connection to Milvus server '{}:{}' with alias '{:s}'" + .format(MILVUS_HOST, MILVUS_PORT, self.alias)) + except Exception as e: + logger.error("Failed to create connection to Milvus server '{}:{}', error: {}" + .format(MILVUS_HOST, MILVUS_PORT, e)) + + def _create_collection(self, collection_name, create_new: bool) -> None: + """Create a collection based on environment and passed in variables. + + Args: + create_new (bool): Whether to overwrite if collection already exists. + """ + try: + self._schema_ver = "V1" + # If the collection exists and create_new is True, drop the existing collection + if utility.has_collection(collection_name, using=self.alias) and create_new: + utility.drop_collection(collection_name, using=self.alias) + + # Check if the collection doesnt exist + if utility.has_collection(collection_name, using=self.alias) is False: + # If it doesnt exist use the field params from init to create a new schem + schema = [field[1] for field in SCHEMA_V2] + schema = CollectionSchema(schema) + # Use the schema to create a new collection + self.col = Collection( + collection_name, + schema=schema, + using=self.alias, + consistency_level=self._consistency_level, + ) + self._schema_ver = "V2" + logger.info("Create Milvus collection '{}' with schema {} and consistency level {}" + .format(collection_name, self._schema_ver, self._consistency_level)) + else: + # If the collection exists, point to it + self.col = Collection( + collection_name, using=self.alias + ) # type: ignore + # Which sechma is used + for field in self.col.schema.fields: + if field.name == "id" and field.is_primary: + self._schema_ver = "V2" + break + logger.info("Milvus collection '{}' already exists with schema {}" + .format(collection_name, self._schema_ver)) + except Exception as e: + logger.error("Failed to create collection '{}', error: {}".format(collection_name, e)) + + def _create_index(self): + # TODO: verify index/search params passed by os.environ + self.index_params = MILVUS_INDEX_PARAMS or None + self.search_params = MILVUS_SEARCH_PARAMS or None + try: + # If no index on the collection, create one + if len(self.col.indexes) == 0: + if self.index_params is not None: + # Convert the string format to JSON format parameters passed by MILVUS_INDEX_PARAMS + self.index_params = json.loads(self.index_params) + logger.info("Create Milvus index: {}".format(self.index_params)) + # Create an index on the 'embedding' field with the index params found in init + self.col.create_index(EMBEDDING_FIELD, index_params=self.index_params) + else: + # If no index param supplied, to first create an HNSW index for Milvus + try: + i_p = { + "metric_type": "IP", + "index_type": "HNSW", + "params": {"M": 8, "efConstruction": 64}, + } + logger.info("Attempting creation of Milvus '{}' index".format(i_p["index_type"])) + self.col.create_index(EMBEDDING_FIELD, index_params=i_p) + self.index_params = i_p + logger.info("Creation of Milvus '{}' index successful".format(i_p["index_type"])) + # If create fails, most likely due to being Zilliz Cloud instance, try to create an AutoIndex + except MilvusException: + logger.info("Attempting creation of Milvus default index") + i_p = {"metric_type": "IP", "index_type": "AUTOINDEX", "params": {}} + self.col.create_index(EMBEDDING_FIELD, index_params=i_p) + self.index_params = i_p + logger.info("Creation of Milvus default index successful") + # If an index already exists, grab its params + else: + # How about if the first index is not vector index? + for index in self.col.indexes: + idx = index.to_dict() + if idx["field"] == EMBEDDING_FIELD: + logger.info("Index already exists: {}".format(idx)) + self.index_params = idx['index_param'] + break + + self.col.load() + + if self.search_params is not None: + # Convert the string format to JSON format parameters passed by MILVUS_SEARCH_PARAMS + self.search_params = json.loads(self.search_params) + else: + # The default search params + metric_type = "IP" + if "metric_type" in self.index_params: + metric_type = self.index_params["metric_type"] + default_search_params = { + "IVF_FLAT": {"metric_type": metric_type, "params": {"nprobe": 10}}, + "IVF_SQ8": {"metric_type": metric_type, "params": {"nprobe": 10}}, + "IVF_PQ": {"metric_type": metric_type, "params": {"nprobe": 10}}, + "HNSW": {"metric_type": metric_type, "params": {"ef": 10}}, + "RHNSW_FLAT": {"metric_type": metric_type, "params": {"ef": 10}}, + "RHNSW_SQ": {"metric_type": metric_type, "params": {"ef": 10}}, + "RHNSW_PQ": {"metric_type": metric_type, "params": {"ef": 10}}, + "IVF_HNSW": {"metric_type": metric_type, "params": {"nprobe": 10, "ef": 10}}, + "ANNOY": {"metric_type": metric_type, "params": {"search_k": 10}}, + "AUTOINDEX": {"metric_type": metric_type, "params": {}}, + } + # Set the search params + self.search_params = default_search_params[self.index_params["index_type"]] + logger.info("Milvus search parameters: {}".format(self.search_params)) + except Exception as e: + logger.error("Failed to create index, error: {}".format(e)) + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """Upsert chunks into the datastore. + + Args: + chunks (Dict[str, List[DocumentChunk]]): A list of DocumentChunks to insert + + Raises: + e: Error in upserting data. + + Returns: + List[str]: The document_id's that were inserted. + """ + try: + # The doc id's to return for the upsert + doc_ids: List[str] = [] + # List to collect all the insert data, skip the "pk" for schema V1 + offset = 1 if self._schema_ver == "V1" else 0 + insert_data = [[] for _ in range(len(self._get_schema()) - offset)] + + # Go through each document chunklist and grab the data + for doc_id, chunk_list in chunks.items(): + # Append the doc_id to the list we are returning + doc_ids.append(doc_id) + # Examine each chunk in the chunklist + for chunk in chunk_list: + # Extract data from the chunk + list_of_data = self._get_values(chunk) + # Check if the data is valid + if list_of_data is not None: + # Append each field to the insert_data + for x in range(len(insert_data)): + insert_data[x].append(list_of_data[x]) + # Slice up our insert data into batches + batches = [ + insert_data[i : i + UPSERT_BATCH_SIZE] + for i in range(0, len(insert_data), UPSERT_BATCH_SIZE) + ] + + # Attempt to insert each batch into our collection + # batch data can work with both V1 and V2 schema + for batch in batches: + if len(batch[0]) != 0: + try: + logger.info(f"Upserting batch of size {len(batch[0])}") + self.col.insert(batch) + logger.info(f"Upserted batch successfully") + except Exception as e: + logger.error(f"Failed to insert batch records, error: {e}") + raise e + + # This setting perfoms flushes after insert. Small insert == bad to use + # self.col.flush() + return doc_ids + except Exception as e: + logger.error("Failed to insert records, error: {}".format(e)) + return [] + + + def _get_values(self, chunk: DocumentChunk) -> List[any] | None: # type: ignore + """Convert the chunk into a list of values to insert whose indexes align with fields. + + Args: + chunk (DocumentChunk): The chunk to convert. + + Returns: + List (any): The values to insert. + """ + # Convert DocumentChunk and its sub models to dict + values = chunk.dict() + # Unpack the metadata into the same dict + meta = values.pop("metadata") + values.update(meta) + + # Convert date to int timestamp form + if values["created_at"]: + values["created_at"] = to_unix_timestamp(values["created_at"]) + + # If source exists, change from Source object to the string value it holds + if values["source"]: + values["source"] = values["source"].value + # List to collect data we will return + ret = [] + # Grab data responding to each field, excluding the hidden auto pk field for schema V1 + offset = 1 if self._schema_ver == "V1" else 0 + for key, _, default in self._get_schema()[offset:]: + # Grab the data at the key and default to our defaults set in init + x = values.get(key) or default + # If one of our required fields is missing, ignore the entire entry + if x is Required: + logger.info("Chunk " + values["id"] + " missing " + key + " skipping") + return None + # Add the corresponding value if it passes the tests + ret.append(x) + return ret + + async def _query( + self, + queries: List[QueryWithEmbedding], + ) -> List[QueryResult]: + """Query the QueryWithEmbedding against the MilvusDocumentSearch + + Search the embedding and its filter in the collection. + + Args: + queries (List[QueryWithEmbedding]): The list of searches to perform. + + Returns: + List[QueryResult]: Results for each search. + """ + # Async to perform the query, adapted from pinecone implementation + async def _single_query(query: QueryWithEmbedding) -> QueryResult: + try: + filter = None + # Set the filter to expression that is valid for Milvus + if query.filter is not None: + # Either a valid filter or None will be returned + filter = self._get_filter(query.filter) + + # Perform our search + return_from = 2 if self._schema_ver == "V1" else 1 + res = self.col.search( + data=[query.embedding], + anns_field=EMBEDDING_FIELD, + param=self.search_params, + limit=query.top_k, + expr=filter, + output_fields=[ + field[0] for field in self._get_schema()[return_from:] + ], # Ignoring pk, embedding + ) + # Results that will hold our DocumentChunkWithScores + results = [] + # Parse every result for our search + for hit in res[0]: # type: ignore + # The distance score for the search result, falls under DocumentChunkWithScore + score = hit.score + # Our metadata info, falls under DocumentChunkMetadata + metadata = {} + # Grab the values that correspond to our fields, ignore pk and embedding. + for x in [field[0] for field in self._get_schema()[return_from:]]: + metadata[x] = hit.entity.get(x) + # If the source isn't valid, convert to None + if metadata["source"] not in Source.__members__: + metadata["source"] = None + # Text falls under the DocumentChunk + text = metadata.pop("text") + # Id falls under the DocumentChunk + ids = metadata.pop("id") + chunk = DocumentChunkWithScore( + id=ids, + score=score, + text=text, + metadata=DocumentChunkMetadata(**metadata), + ) + results.append(chunk) + + # TODO: decide on doing queries to grab the embedding itself, slows down performance as double query occurs + + return QueryResult(query=query.query, results=results) + except Exception as e: + logger.error("Failed to query, error: {}".format(e)) + return QueryResult(query=query.query, results=[]) + + results: List[QueryResult] = await asyncio.gather( + *[_single_query(query) for query in queries] + ) + return results + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """Delete the entities based either on the chunk_id of the vector, + + Args: + ids (Optional[List[str]], optional): The document_ids to delete. Defaults to None. + filter (Optional[DocumentMetadataFilter], optional): The filter to delete by. Defaults to None. + delete_all (Optional[bool], optional): Whether to drop the collection and recreate it. Defaults to None. + """ + # If deleting all, drop and create the new collection + if delete_all: + coll_name = self.col.name + logger.info("Delete the entire collection {} and create new one".format(coll_name)) + # Release the collection from memory + self.col.release() + # Drop the collection + self.col.drop() + # Recreate the new collection + self._create_collection(coll_name, True) + self._create_index() + return True + + # Keep track of how many we have deleted for later printing + delete_count = 0 + batch_size = 100 + pk_name = "pk" if self._schema_ver == "V1" else "id" + try: + # According to the api design, the ids is a list of document_id, + # document_id is not primary key, use query+delete to workaround, + # in future version we can delete by expression + if (ids is not None) and len(ids) > 0: + # Add quotation marks around the string format id + ids = ['"' + str(id) + '"' for id in ids] + # Query for the pk's of entries that match id's + ids = self.col.query(f"document_id in [{','.join(ids)}]") + # Convert to list of pks + pks = [str(entry[pk_name]) for entry in ids] # type: ignore + # for schema V2, the "id" is varchar, rewrite the expression + if self._schema_ver != "V1": + pks = ['"' + pk + '"' for pk in pks] + + # Delete by ids batch by batch(avoid too long expression) + logger.info("Apply {:d} deletions to schema {:s}".format(len(pks), self._schema_ver)) + while len(pks) > 0: + batch_pks = pks[:batch_size] + pks = pks[batch_size:] + # Delete the entries batch by batch + res = self.col.delete(f"{pk_name} in [{','.join(batch_pks)}]") + # Increment our deleted count + delete_count += int(res.delete_count) # type: ignore + except Exception as e: + logger.error("Failed to delete by ids, error: {}".format(e)) + + try: + # Check if empty filter + if filter is not None: + # Convert filter to milvus expression + filter = self._get_filter(filter) # type: ignore + # Check if there is anything to filter + if len(filter) != 0: # type: ignore + # Query for the pk's of entries that match filter + res = self.col.query(filter) # type: ignore + # Convert to list of pks + pks = [str(entry[pk_name]) for entry in res] # type: ignore + # for schema V2, the "id" is varchar, rewrite the expression + if self._schema_ver != "V1": + pks = ['"' + pk + '"' for pk in pks] + # Check to see if there are valid pk's to delete, delete batch by batch(avoid too long expression) + while len(pks) > 0: # type: ignore + batch_pks = pks[:batch_size] + pks = pks[batch_size:] + # Delete the entries batch by batch + res = self.col.delete(f"{pk_name} in [{','.join(batch_pks)}]") # type: ignore + # Increment our delete count + delete_count += int(res.delete_count) # type: ignore + except Exception as e: + logger.error("Failed to delete by filter, error: {}".format(e)) + + logger.info("{:d} records deleted".format(delete_count)) + + # This setting performs flushes after delete. Small delete == bad to use + # self.col.flush() + + return True + + def _get_filter(self, filter: DocumentMetadataFilter) -> Optional[str]: + """Converts a DocumentMetdataFilter to the expression that Milvus takes. + + Args: + filter (DocumentMetadataFilter): The Filter to convert to Milvus expression. + + Returns: + Optional[str]: The filter if valid, otherwise None. + """ + filters = [] + # Go through all the fields and their values + for field, value in filter.dict().items(): + # Check if the Value is empty + if value is not None: + # Convert start_date to int and add greater than or equal logic + if field == "start_date": + filters.append( + "(created_at >= " + str(to_unix_timestamp(value)) + ")" + ) + # Convert end_date to int and add less than or equal logic + elif field == "end_date": + filters.append( + "(created_at <= " + str(to_unix_timestamp(value)) + ")" + ) + # Convert Source to its string value and check equivalency + elif field == "source": + filters.append("(" + field + ' == "' + str(value.value) + '")') + # Check equivalency of rest of string fields + else: + filters.append("(" + field + ' == "' + str(value) + '")') + # Join all our expressions with `and`` + return " and ".join(filters) diff --git a/datastore/providers/pgvector_datastore.py b/datastore/providers/pgvector_datastore.py new file mode 100644 index 000000000..cd7026b23 --- /dev/null +++ b/datastore/providers/pgvector_datastore.py @@ -0,0 +1,181 @@ +from abc import ABC, abstractmethod +from typing import Any, Dict, List, Optional +from datetime import datetime +from loguru import logger + +from services.date import to_unix_timestamp +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + DocumentChunkWithScore, +) + + +# interface for Postgres client to implement pg based Datastore providers +class PGClient(ABC): + @abstractmethod + async def upsert(self, table: str, json: dict[str, Any]) -> None: + """ + Takes in a list of documents and inserts them into the table. + """ + raise NotImplementedError + + @abstractmethod + async def rpc(self, function_name: str, params: dict[str, Any]) -> Any: + """ + Calls a stored procedure in the database with the given parameters. + """ + raise NotImplementedError + + @abstractmethod + async def delete_like(self, table: str, column: str, pattern: str) -> None: + """ + Deletes rows in the table that match the pattern. + """ + raise NotImplementedError + + @abstractmethod + async def delete_in(self, table: str, column: str, ids: List[str]) -> None: + """ + Deletes rows in the table that match the ids. + """ + raise NotImplementedError + + @abstractmethod + async def delete_by_filters( + self, table: str, filter: DocumentMetadataFilter + ) -> None: + """ + Deletes rows in the table that match the filter. + """ + raise NotImplementedError + + +# abstract class for Postgres based Datastore providers that implements DataStore interface +class PgVectorDataStore(DataStore): + def __init__(self): + self.client = self.create_db_client() + + @abstractmethod + def create_db_client(self) -> PGClient: + """ + Create db client, can be accessing postgres database via different APIs. + Can be supabase client or psycopg2 based client. + Return a client for postgres DB. + """ + + raise NotImplementedError + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a dict of document_ids to list of document chunks and inserts them into the database. + Return a list of document ids. + """ + for document_id, document_chunks in chunks.items(): + for chunk in document_chunks: + json = { + "id": chunk.id, + "content": chunk.text, + "embedding": chunk.embedding, + "document_id": document_id, + "source": chunk.metadata.source, + "source_id": chunk.metadata.source_id, + "url": chunk.metadata.url, + "author": chunk.metadata.author, + } + if chunk.metadata.created_at: + json["created_at"] = ( + datetime.fromtimestamp( + to_unix_timestamp(chunk.metadata.created_at) + ), + ) + await self.client.upsert("documents", json) + + return list(chunks.keys()) + + async def _query(self, queries: List[QueryWithEmbedding]) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + query_results: List[QueryResult] = [] + for query in queries: + # get the top 3 documents with the highest cosine similarity using rpc function in the database called "match_page_sections" + params = { + "in_embedding": query.embedding, + } + if query.top_k: + params["in_match_count"] = query.top_k + if query.filter: + if query.filter.document_id: + params["in_document_id"] = query.filter.document_id + if query.filter.source: + params["in_source"] = query.filter.source.value + if query.filter.source_id: + params["in_source_id"] = query.filter.source_id + if query.filter.author: + params["in_author"] = query.filter.author + if query.filter.start_date: + params["in_start_date"] = datetime.fromtimestamp( + to_unix_timestamp(query.filter.start_date) + ) + if query.filter.end_date: + params["in_end_date"] = datetime.fromtimestamp( + to_unix_timestamp(query.filter.end_date) + ) + try: + data = await self.client.rpc("match_page_sections", params=params) + results: List[DocumentChunkWithScore] = [] + for row in data: + document_chunk = DocumentChunkWithScore( + id=row["id"], + text=row["content"], + # TODO: add embedding to the response ? + # embedding=row["embedding"], + score=float(row["similarity"]), + metadata=DocumentChunkMetadata( + source=row["source"], + source_id=row["source_id"], + document_id=row["document_id"], + url=row["url"], + created_at=row["created_at"], + author=row["author"], + ), + ) + results.append(document_chunk) + query_results.append(QueryResult(query=query.query, results=results)) + except Exception as e: + logger.error(e) + query_results.append(QueryResult(query=query.query, results=[])) + return query_results + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything in the datastore. + Multiple parameters can be used at once. + Returns whether the operation was successful. + """ + if delete_all: + try: + await self.client.delete_like("documents", "document_id", "%") + except: + return False + elif ids: + try: + await self.client.delete_in("documents", "document_id", ids) + except: + return False + elif filter: + try: + await self.client.delete_by_filters("documents", filter) + except: + return False + return True diff --git a/datastore/providers/pinecone_datastore.py b/datastore/providers/pinecone_datastore.py new file mode 100644 index 000000000..c10ee2bea --- /dev/null +++ b/datastore/providers/pinecone_datastore.py @@ -0,0 +1,262 @@ +import os +from typing import Any, Dict, List, Optional +import pinecone +from tenacity import retry, wait_random_exponential, stop_after_attempt +import asyncio +from loguru import logger + +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + DocumentChunkWithScore, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + Source, +) +from services.date import to_unix_timestamp + +# Read environment variables for Pinecone configuration +PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY") +PINECONE_ENVIRONMENT = os.environ.get("PINECONE_ENVIRONMENT") +PINECONE_INDEX = os.environ.get("PINECONE_INDEX") +assert PINECONE_API_KEY is not None +assert PINECONE_ENVIRONMENT is not None +assert PINECONE_INDEX is not None + +# Initialize Pinecone with the API key and environment +pinecone.init(api_key=PINECONE_API_KEY, environment=PINECONE_ENVIRONMENT) + +# Set the batch size for upserting vectors to Pinecone +UPSERT_BATCH_SIZE = 100 + + +class PineconeDataStore(DataStore): + def __init__(self): + # Check if the index name is specified and exists in Pinecone + if PINECONE_INDEX and PINECONE_INDEX not in pinecone.list_indexes(): + + # Get all fields in the metadata object in a list + fields_to_index = list(DocumentChunkMetadata.__fields__.keys()) + + # Create a new index with the specified name, dimension, and metadata configuration + try: + logger.info( + f"Creating index {PINECONE_INDEX} with metadata config {fields_to_index}" + ) + pinecone.create_index( + PINECONE_INDEX, + dimension=1536, # dimensionality of OpenAI ada v2 embeddings + metadata_config={"indexed": fields_to_index}, + ) + self.index = pinecone.Index(PINECONE_INDEX) + logger.info(f"Index {PINECONE_INDEX} created successfully") + except Exception as e: + logger.error(f"Error creating index {PINECONE_INDEX}: {e}") + raise e + elif PINECONE_INDEX and PINECONE_INDEX in pinecone.list_indexes(): + # Connect to an existing index with the specified name + try: + logger.info(f"Connecting to existing index {PINECONE_INDEX}") + self.index = pinecone.Index(PINECONE_INDEX) + logger.info(f"Connected to index {PINECONE_INDEX} successfully") + except Exception as e: + logger.error(f"Error connecting to index {PINECONE_INDEX}: {e}") + raise e + + @retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(3)) + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a dict from document id to list of document chunks and inserts them into the index. + Return a list of document ids. + """ + # Initialize a list of ids to return + doc_ids: List[str] = [] + # Initialize a list of vectors to upsert + vectors = [] + # Loop through the dict items + for doc_id, chunk_list in chunks.items(): + # Append the id to the ids list + doc_ids.append(doc_id) + logger.info(f"Upserting document_id: {doc_id}") + for chunk in chunk_list: + # Create a vector tuple of (id, embedding, metadata) + # Convert the metadata object to a dict with unix timestamps for dates + pinecone_metadata = self._get_pinecone_metadata(chunk.metadata) + # Add the text and document id to the metadata dict + pinecone_metadata["text"] = chunk.text + pinecone_metadata["document_id"] = doc_id + vector = (chunk.id, chunk.embedding, pinecone_metadata) + vectors.append(vector) + + # Split the vectors list into batches of the specified size + batches = [ + vectors[i : i + UPSERT_BATCH_SIZE] + for i in range(0, len(vectors), UPSERT_BATCH_SIZE) + ] + # Upsert each batch to Pinecone + for batch in batches: + try: + logger.info(f"Upserting batch of size {len(batch)}") + self.index.upsert(vectors=batch) + logger.info(f"Upserted batch successfully") + except Exception as e: + logger.error(f"Error upserting batch: {e}") + raise e + + return doc_ids + + @retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(3)) + async def _query( + self, + queries: List[QueryWithEmbedding], + ) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + + # Define a helper coroutine that performs a single query and returns a QueryResult + async def _single_query(query: QueryWithEmbedding) -> QueryResult: + logger.debug(f"Query: {query.query}") + + # Convert the metadata filter object to a dict with pinecone filter expressions + pinecone_filter = self._get_pinecone_filter(query.filter) + + try: + # Query the index with the query embedding, filter, and top_k + query_response = self.index.query( + # namespace=namespace, + top_k=query.top_k, + vector=query.embedding, + filter=pinecone_filter, + include_metadata=True, + ) + except Exception as e: + logger.error(f"Error querying index: {e}") + raise e + + query_results: List[DocumentChunkWithScore] = [] + for result in query_response.matches: + score = result.score + metadata = result.metadata + # Remove document id and text from metadata and store it in a new variable + metadata_without_text = ( + {key: value for key, value in metadata.items() if key != "text"} + if metadata + else None + ) + + # If the source is not a valid Source in the Source enum, set it to None + if ( + metadata_without_text + and "source" in metadata_without_text + and metadata_without_text["source"] not in Source.__members__ + ): + metadata_without_text["source"] = None + + # Create a document chunk with score object with the result data + result = DocumentChunkWithScore( + id=result.id, + score=score, + text=metadata["text"] if metadata and "text" in metadata else None, + metadata=metadata_without_text, + ) + query_results.append(result) + return QueryResult(query=query.query, results=query_results) + + # Use asyncio.gather to run multiple _single_query coroutines concurrently and collect their results + results: List[QueryResult] = await asyncio.gather( + *[_single_query(query) for query in queries] + ) + + return results + + @retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(3)) + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything from the index. + """ + # Delete all vectors from the index if delete_all is True + if delete_all: + try: + logger.info(f"Deleting all vectors from index") + self.index.delete(delete_all=True) + logger.info(f"Deleted all vectors successfully") + return True + except Exception as e: + logger.error(f"Error deleting all vectors: {e}") + raise e + + # Convert the metadata filter object to a dict with pinecone filter expressions + pinecone_filter = self._get_pinecone_filter(filter) + # Delete vectors that match the filter from the index if the filter is not empty + if pinecone_filter != {}: + try: + logger.info(f"Deleting vectors with filter {pinecone_filter}") + self.index.delete(filter=pinecone_filter) + logger.info(f"Deleted vectors with filter successfully") + except Exception as e: + logger.error(f"Error deleting vectors with filter: {e}") + raise e + + # Delete vectors that match the document ids from the index if the ids list is not empty + if ids is not None and len(ids) > 0: + try: + logger.info(f"Deleting vectors with ids {ids}") + pinecone_filter = {"document_id": {"$in": ids}} + self.index.delete(filter=pinecone_filter) # type: ignore + logger.info(f"Deleted vectors with ids successfully") + except Exception as e: + logger.error(f"Error deleting vectors with ids: {e}") + raise e + + return True + + def _get_pinecone_filter( + self, filter: Optional[DocumentMetadataFilter] = None + ) -> Dict[str, Any]: + if filter is None: + return {} + + pinecone_filter = {} + + # For each field in the MetadataFilter, check if it has a value and add the corresponding pinecone filter expression + # For start_date and end_date, uses the $gte and $lte operators respectively + # For other fields, uses the $eq operator + for field, value in filter.dict().items(): + if value is not None: + if field == "start_date": + pinecone_filter["date"] = pinecone_filter.get("date", {}) + pinecone_filter["date"]["$gte"] = to_unix_timestamp(value) + elif field == "end_date": + pinecone_filter["date"] = pinecone_filter.get("date", {}) + pinecone_filter["date"]["$lte"] = to_unix_timestamp(value) + else: + pinecone_filter[field] = value + + return pinecone_filter + + def _get_pinecone_metadata( + self, metadata: Optional[DocumentChunkMetadata] = None + ) -> Dict[str, Any]: + if metadata is None: + return {} + + pinecone_metadata = {} + + # For each field in the Metadata, check if it has a value and add it to the pinecone metadata dict + # For fields that are dates, convert them to unix timestamps + for field, value in metadata.dict().items(): + if value is not None: + if field in ["created_at"]: + pinecone_metadata[field] = to_unix_timestamp(value) + else: + pinecone_metadata[field] = value + + return pinecone_metadata diff --git a/datastore/providers/postgres_datastore.py b/datastore/providers/postgres_datastore.py new file mode 100644 index 000000000..402ad1b28 --- /dev/null +++ b/datastore/providers/postgres_datastore.py @@ -0,0 +1,132 @@ +import os +from typing import Any, List +from datetime import datetime +import numpy as np + +from psycopg2 import connect +from psycopg2.extras import DictCursor +from pgvector.psycopg2 import register_vector + +from services.date import to_unix_timestamp +from datastore.providers.pgvector_datastore import PGClient, PgVectorDataStore +from models.models import ( + DocumentMetadataFilter, +) + +PG_HOST = os.environ.get("PG_HOST", "localhost") +PG_PORT = int(os.environ.get("PG_PORT", 5432)) +PG_DB = os.environ.get("PG_DB", "postgres") +PG_USER = os.environ.get("PG_USER", "postgres") +PG_PASSWORD = os.environ.get("PG_PASSWORD", "postgres") + + +# class that implements the DataStore interface for Postgres Datastore provider +class PostgresDataStore(PgVectorDataStore): + def create_db_client(self): + return PostgresClient() + + +class PostgresClient(PGClient): + def __init__(self) -> None: + super().__init__() + self.client = connect( + dbname=PG_DB, user=PG_USER, password=PG_PASSWORD, host=PG_HOST, port=PG_PORT + ) + register_vector(self.client) + + def __del__(self): + # close the connection when the client is destroyed + self.client.close() + + async def upsert(self, table: str, json: dict[str, Any]): + """ + Takes in a list of documents and inserts them into the table. + """ + with self.client.cursor() as cur: + if not json.get("created_at"): + json["created_at"] = datetime.now() + json["embedding"] = np.array(json["embedding"]) + cur.execute( + f"INSERT INTO {table} (id, content, embedding, document_id, source, source_id, url, author, created_at) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) ON CONFLICT (id) DO UPDATE SET content = %s, embedding = %s, document_id = %s, source = %s, source_id = %s, url = %s, author = %s, created_at = %s", + ( + json["id"], + json["content"], + json["embedding"], + json["document_id"], + json["source"], + json["source_id"], + json["url"], + json["author"], + json["created_at"], + json["content"], + json["embedding"], + json["document_id"], + json["source"], + json["source_id"], + json["url"], + json["author"], + json["created_at"], + ), + ) + self.client.commit() + + async def rpc(self, function_name: str, params: dict[str, Any]): + """ + Calls a stored procedure in the database with the given parameters. + """ + data = [] + params["in_embedding"] = np.array(params["in_embedding"]) + with self.client.cursor(cursor_factory=DictCursor) as cur: + cur.callproc(function_name, params) + rows = cur.fetchall() + self.client.commit() + for row in rows: + row["created_at"] = to_unix_timestamp(row["created_at"]) + data.append(dict(row)) + return data + + async def delete_like(self, table: str, column: str, pattern: str): + """ + Deletes rows in the table that match the pattern. + """ + with self.client.cursor() as cur: + cur.execute( + f"DELETE FROM {table} WHERE {column} LIKE %s", + (f"%{pattern}%",), + ) + self.client.commit() + + async def delete_in(self, table: str, column: str, ids: List[str]): + """ + Deletes rows in the table that match the ids. + """ + with self.client.cursor() as cur: + cur.execute( + f"DELETE FROM {table} WHERE {column} IN %s", + (tuple(ids),), + ) + self.client.commit() + + async def delete_by_filters(self, table: str, filter: DocumentMetadataFilter): + """ + Deletes rows in the table that match the filter. + """ + + filters = "WHERE" + if filter.document_id: + filters += f" document_id = '{filter.document_id}' AND" + if filter.source: + filters += f" source = '{filter.source}' AND" + if filter.source_id: + filters += f" source_id = '{filter.source_id}' AND" + if filter.author: + filters += f" author = '{filter.author}' AND" + if filter.start_date: + filters += f" created_at >= '{filter.start_date}' AND" + if filter.end_date: + filters += f" created_at <= '{filter.end_date}' AND" + filters = filters[:-4] + + with self.client.cursor() as cur: + cur.execute(f"DELETE FROM {table} {filters}") + self.client.commit() diff --git a/datastore/providers/qdrant_datastore.py b/datastore/providers/qdrant_datastore.py new file mode 100644 index 000000000..ffdfdfb01 --- /dev/null +++ b/datastore/providers/qdrant_datastore.py @@ -0,0 +1,297 @@ +import os +import uuid +from typing import Dict, List, Optional + +from grpc._channel import _InactiveRpcError +from qdrant_client.http.exceptions import UnexpectedResponse +from qdrant_client.http.models import PayloadSchemaType + +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + DocumentChunkWithScore, +) +from qdrant_client.http import models as rest + +import qdrant_client + +from services.date import to_unix_timestamp + +QDRANT_URL = os.environ.get("QDRANT_URL", "http://localhost") +QDRANT_PORT = os.environ.get("QDRANT_PORT", "6333") +QDRANT_GRPC_PORT = os.environ.get("QDRANT_GRPC_PORT", "6334") +QDRANT_API_KEY = os.environ.get("QDRANT_API_KEY") +QDRANT_COLLECTION = os.environ.get("QDRANT_COLLECTION", "document_chunks") + + +class QdrantDataStore(DataStore): + UUID_NAMESPACE = uuid.UUID("3896d314-1e95-4a3a-b45a-945f9f0b541d") + + def __init__( + self, + collection_name: Optional[str] = None, + vector_size: int = 1536, + distance: str = "Cosine", + recreate_collection: bool = False, + ): + """ + Args: + collection_name: Name of the collection to be used + vector_size: Size of the embedding stored in a collection + distance: + Any of "Cosine" / "Euclid" / "Dot". Distance function to measure + similarity + """ + self.client = qdrant_client.QdrantClient( + url=QDRANT_URL, + port=int(QDRANT_PORT), + grpc_port=int(QDRANT_GRPC_PORT), + api_key=QDRANT_API_KEY, + prefer_grpc=True, + timeout=10, + ) + self.collection_name = collection_name or QDRANT_COLLECTION + + # Set up the collection so the points might be inserted or queried + self._set_up_collection(vector_size, distance, recreate_collection) + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a list of document chunks and inserts them into the database. + Return a list of document ids. + """ + points = [ + self._convert_document_chunk_to_point(chunk) + for _, chunks in chunks.items() + for chunk in chunks + ] + self.client.upsert( + collection_name=self.collection_name, + points=points, # type: ignore + wait=True, + ) + return list(chunks.keys()) + + async def _query( + self, + queries: List[QueryWithEmbedding], + ) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + search_requests = [ + self._convert_query_to_search_request(query) for query in queries + ] + results = self.client.search_batch( + collection_name=self.collection_name, + requests=search_requests, + ) + return [ + QueryResult( + query=query.query, + results=[ + self._convert_scored_point_to_document_chunk_with_score(point) + for point in result + ], + ) + for query, result in zip(queries, results) + ] + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything in the datastore. + Returns whether the operation was successful. + """ + if ids is None and filter is None and delete_all is None: + raise ValueError( + "Please provide one of the parameters: ids, filter or delete_all." + ) + + if delete_all: + points_selector = rest.Filter() + else: + points_selector = self._convert_metadata_filter_to_qdrant_filter( + filter, ids + ) + + response = self.client.delete( + collection_name=self.collection_name, + points_selector=points_selector, # type: ignore + ) + return "COMPLETED" == response.status + + def _convert_document_chunk_to_point( + self, document_chunk: DocumentChunk + ) -> rest.PointStruct: + created_at = ( + to_unix_timestamp(document_chunk.metadata.created_at) + if document_chunk.metadata.created_at is not None + else None + ) + return rest.PointStruct( + id=self._create_document_chunk_id(document_chunk.id), + vector=document_chunk.embedding, # type: ignore + payload={ + "id": document_chunk.id, + "text": document_chunk.text, + "metadata": document_chunk.metadata.dict(), + "created_at": created_at, + }, + ) + + def _create_document_chunk_id(self, external_id: Optional[str]) -> str: + if external_id is None: + return uuid.uuid4().hex + return uuid.uuid5(self.UUID_NAMESPACE, external_id).hex + + def _convert_query_to_search_request( + self, query: QueryWithEmbedding + ) -> rest.SearchRequest: + return rest.SearchRequest( + vector=query.embedding, + filter=self._convert_metadata_filter_to_qdrant_filter(query.filter), + limit=query.top_k, # type: ignore + with_payload=True, + with_vector=False, + ) + + def _convert_metadata_filter_to_qdrant_filter( + self, + metadata_filter: Optional[DocumentMetadataFilter] = None, + ids: Optional[List[str]] = None, + ) -> Optional[rest.Filter]: + if metadata_filter is None and ids is None: + return None + + must_conditions, should_conditions = [], [] + + # Filtering by document ids + if ids and len(ids) > 0: + for document_id in ids: + should_conditions.append( + rest.FieldCondition( + key="metadata.document_id", + match=rest.MatchValue(value=document_id), + ) + ) + + # Equality filters for the payload attributes + if metadata_filter: + meta_attributes_keys = { + "document_id": "metadata.document_id", + "source": "metadata.source", + "source_id": "metadata.source_id", + "author": "metadata.author", + } + + for meta_attr_name, payload_key in meta_attributes_keys.items(): + attr_value = getattr(metadata_filter, meta_attr_name) + if attr_value is None: + continue + + must_conditions.append( + rest.FieldCondition( + key=payload_key, match=rest.MatchValue(value=attr_value) + ) + ) + + # Date filters use range filtering + start_date = metadata_filter.start_date + end_date = metadata_filter.end_date + if start_date or end_date: + gte_filter = ( + to_unix_timestamp(start_date) if start_date is not None else None + ) + lte_filter = ( + to_unix_timestamp(end_date) if end_date is not None else None + ) + must_conditions.append( + rest.FieldCondition( + key="created_at", + range=rest.Range( + gte=gte_filter, + lte=lte_filter, + ), + ) + ) + + if 0 == len(must_conditions) and 0 == len(should_conditions): + return None + + return rest.Filter(must=must_conditions, should=should_conditions) + + def _convert_scored_point_to_document_chunk_with_score( + self, scored_point: rest.ScoredPoint + ) -> DocumentChunkWithScore: + payload = scored_point.payload or {} + return DocumentChunkWithScore( + id=payload.get("id"), + text=scored_point.payload.get("text"), # type: ignore + metadata=scored_point.payload.get("metadata"), # type: ignore + embedding=scored_point.vector, # type: ignore + score=scored_point.score, + ) + + def _set_up_collection( + self, vector_size: int, distance: str, recreate_collection: bool + ): + distance = rest.Distance[distance.upper()] + + if recreate_collection: + self._recreate_collection(distance, vector_size) + + try: + collection_info = self.client.get_collection(self.collection_name) + current_distance = collection_info.config.params.vectors.distance # type: ignore + current_vector_size = collection_info.config.params.vectors.size # type: ignore + + if current_distance != distance: + raise ValueError( + f"Collection '{self.collection_name}' already exists in Qdrant, " + f"but it is configured with a similarity '{current_distance.name}'. " + f"If you want to use that collection, but with a different " + f"similarity, please set `recreate_collection=True` argument." + ) + + if current_vector_size != vector_size: + raise ValueError( + f"Collection '{self.collection_name}' already exists in Qdrant, " + f"but it is configured with a vector size '{current_vector_size}'. " + f"If you want to use that collection, but with a different " + f"vector size, please set `recreate_collection=True` argument." + ) + except (UnexpectedResponse, _InactiveRpcError): + self._recreate_collection(distance, vector_size) + + def _recreate_collection(self, distance: rest.Distance, vector_size: int): + self.client.recreate_collection( + self.collection_name, + vectors_config=rest.VectorParams( + size=vector_size, + distance=distance, + ), + ) + + # Create the payload index for the document_id metadata attribute, as it is + # used to delete the document related entries + self.client.create_payload_index( + self.collection_name, + field_name="metadata.document_id", + field_type=PayloadSchemaType.KEYWORD, + ) + + # Create the payload index for the created_at attribute, to make the lookup + # by range filters faster + self.client.create_payload_index( + self.collection_name, + field_name="created_at", + field_schema=PayloadSchemaType.INTEGER, + ) diff --git a/datastore/providers/redis_datastore.py b/datastore/providers/redis_datastore.py new file mode 100644 index 000000000..da13348f7 --- /dev/null +++ b/datastore/providers/redis_datastore.py @@ -0,0 +1,391 @@ +import asyncio +import os +import re +import json +import redis.asyncio as redis +import numpy as np + +from redis.commands.search.query import Query as RediSearchQuery +from redis.commands.search.indexDefinition import IndexDefinition, IndexType +from redis.commands.search.field import ( + TagField, + TextField, + NumericField, + VectorField, +) +from loguru import logger +from typing import Dict, List, Optional +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentMetadataFilter, + DocumentChunkWithScore, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, +) +from services.date import to_unix_timestamp + +# Read environment variables for Redis +REDIS_HOST = os.environ.get("REDIS_HOST", "localhost") +REDIS_PORT = int(os.environ.get("REDIS_PORT", 6379)) +REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD") +REDIS_INDEX_NAME = os.environ.get("REDIS_INDEX_NAME", "index") +REDIS_DOC_PREFIX = os.environ.get("REDIS_DOC_PREFIX", "doc") +REDIS_DISTANCE_METRIC = os.environ.get("REDIS_DISTANCE_METRIC", "COSINE") +REDIS_INDEX_TYPE = os.environ.get("REDIS_INDEX_TYPE", "FLAT") +assert REDIS_INDEX_TYPE in ("FLAT", "HNSW") + +# OpenAI Ada Embeddings Dimension +VECTOR_DIMENSION = 1536 + +# RediSearch constants +REDIS_REQUIRED_MODULES = [ + {"name": "search", "ver": 20600}, + {"name": "ReJSON", "ver": 20404} +] + +REDIS_DEFAULT_ESCAPED_CHARS = re.compile(r"[,.<>{}\[\]\\\"\':;!@#$%^&()\-+=~\/ ]") + +# Helper functions +def unpack_schema(d: dict): + for v in d.values(): + if isinstance(v, dict): + yield from unpack_schema(v) + else: + yield v + +async def _check_redis_module_exist(client: redis.Redis, modules: List[dict]): + installed_modules = (await client.info()).get("modules", []) + installed_modules = {module["name"]: module for module in installed_modules} + for module in modules: + if module["name"] not in installed_modules or int(installed_modules[module["name"]]["ver"]) < int(module["ver"]): + error_message = "You must add the RediSearch (>= 2.6) and ReJSON (>= 2.4) modules from Redis Stack. " \ + "Please refer to Redis Stack docs: https://redis.io/docs/stack/" + logger.error(error_message) + raise AttributeError(error_message) + + +class RedisDataStore(DataStore): + def __init__(self, client: redis.Redis, redisearch_schema: dict): + self.client = client + self._schema = redisearch_schema + # Init default metadata with sentinel values in case the document written has no metadata + self._default_metadata = { + field: (0 if field == "created_at" else "_null_") for field in redisearch_schema["metadata"] + } + + ### Redis Helper Methods ### + + @classmethod + async def init(cls, **kwargs): + """ + Setup the index if it does not exist. + """ + try: + # Connect to the Redis Client + logger.info("Connecting to Redis") + client = redis.Redis( + host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD + ) + except Exception as e: + logger.error(f"Error setting up Redis: {e}") + raise e + + await _check_redis_module_exist(client, modules=REDIS_REQUIRED_MODULES) + + dim = kwargs.get("dim", VECTOR_DIMENSION) + redisearch_schema = { + "metadata": { + "document_id": TagField("$.metadata.document_id", as_name="document_id"), + "source_id": TagField("$.metadata.source_id", as_name="source_id"), + "source": TagField("$.metadata.source", as_name="source"), + "author": TextField("$.metadata.author", as_name="author"), + "created_at": NumericField("$.metadata.created_at", as_name="created_at"), + }, + "embedding": VectorField( + "$.embedding", + REDIS_INDEX_TYPE, + { + "TYPE": "FLOAT64", + "DIM": dim, + "DISTANCE_METRIC": REDIS_DISTANCE_METRIC, + }, + as_name="embedding", + ), + } + try: + # Check for existence of RediSearch Index + await client.ft(REDIS_INDEX_NAME).info() + logger.info(f"RediSearch index {REDIS_INDEX_NAME} already exists") + except: + # Create the RediSearch Index + logger.info(f"Creating new RediSearch index {REDIS_INDEX_NAME}") + definition = IndexDefinition( + prefix=[REDIS_DOC_PREFIX], index_type=IndexType.JSON + ) + fields = list(unpack_schema(redisearch_schema)) + logger.info(f"Creating index with fields: {fields}") + await client.ft(REDIS_INDEX_NAME).create_index( + fields=fields, definition=definition + ) + return cls(client, redisearch_schema) + + @staticmethod + def _redis_key(document_id: str, chunk_id: str) -> str: + """ + Create the JSON key for document chunks in Redis. + + Args: + document_id (str): Document Identifier + chunk_id (str): Chunk Identifier + + Returns: + str: JSON key string. + """ + return f"doc:{document_id}:chunk:{chunk_id}" + + @staticmethod + def _escape(value: str) -> str: + """ + Escape filter value. + + Args: + value (str): Value to escape. + + Returns: + str: Escaped filter value for RediSearch. + """ + + def escape_symbol(match) -> str: + value = match.group(0) + return f"\\{value}" + + return REDIS_DEFAULT_ESCAPED_CHARS.sub(escape_symbol, value) + + def _get_redis_chunk(self, chunk: DocumentChunk) -> dict: + """ + Convert DocumentChunk into a JSON object for storage + in Redis. + + Args: + chunk (DocumentChunk): Chunk of a Document. + + Returns: + dict: JSON object for storage in Redis. + """ + # Convert chunk -> dict + data = chunk.__dict__ + metadata = chunk.metadata.__dict__ + data["chunk_id"] = data.pop("id") + + # Prep Redis Metadata + redis_metadata = dict(self._default_metadata) + if metadata: + for field, value in metadata.items(): + if value: + if field == "created_at": + redis_metadata[field] = to_unix_timestamp(value) # type: ignore + else: + redis_metadata[field] = value + data["metadata"] = redis_metadata + return data + + def _get_redis_query(self, query: QueryWithEmbedding) -> RediSearchQuery: + """ + Convert a QueryWithEmbedding into a RediSearchQuery. + + Args: + query (QueryWithEmbedding): Search query. + + Returns: + RediSearchQuery: Query for RediSearch. + """ + filter_str: str = "" + + # RediSearch field type to query string + def _typ_to_str(typ, field, value) -> str: # type: ignore + if isinstance(typ, TagField): + return f"@{field}:{{{self._escape(value)}}} " + elif isinstance(typ, TextField): + return f"@{field}:{value} " + elif isinstance(typ, NumericField): + num = to_unix_timestamp(value) + match field: + case "start_date": + return f"@{field}:[{num} +inf] " + case "end_date": + return f"@{field}:[-inf {num}] " + + # Build filter + if query.filter: + redisearch_schema = self._schema + for field, value in query.filter.__dict__.items(): + if not value: + continue + if field in redisearch_schema: + filter_str += _typ_to_str(redisearch_schema[field], field, value) + elif field in redisearch_schema["metadata"]: + if field == "source": # handle the enum + value = value.value + filter_str += _typ_to_str( + redisearch_schema["metadata"][field], field, value + ) + elif field in ["start_date", "end_date"]: + filter_str += _typ_to_str( + redisearch_schema["metadata"]["created_at"], field, value + ) + + # Postprocess filter string + filter_str = filter_str.strip() + filter_str = filter_str if filter_str else "*" + + # Prepare query string + query_str = ( + f"({filter_str})=>[KNN {query.top_k} @embedding $embedding as score]" + ) + return ( + RediSearchQuery(query_str) + .sort_by("score") + .paging(0, query.top_k) + .dialect(2) + ) + + async def _redis_delete(self, keys: List[str]): + """ + Delete a list of keys from Redis. + + Args: + keys (List[str]): List of keys to delete. + """ + # Delete the keys + await asyncio.gather(*[self.client.delete(key) for key in keys]) + + ####### + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a list of list of document chunks and inserts them into the database. + Return a list of document ids. + """ + # Initialize a list of ids to return + doc_ids: List[str] = [] + + # Loop through the dict items + for doc_id, chunk_list in chunks.items(): + + # Append the id to the ids list + doc_ids.append(doc_id) + + # Write chunks in a pipelines + async with self.client.pipeline(transaction=False) as pipe: + for chunk in chunk_list: + key = self._redis_key(doc_id, chunk.id) + data = self._get_redis_chunk(chunk) + await pipe.json().set(key, "$", data) + await pipe.execute() + + return doc_ids + + async def _query( + self, + queries: List[QueryWithEmbedding], + ) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and + returns a list of query results with matching document chunks and scores. + """ + # Prepare query responses and results object + results: List[QueryResult] = [] + + # Gather query results in a pipeline + logger.info(f"Gathering {len(queries)} query results") + for query in queries: + + logger.debug(f"Query: {query.query}") + query_results: List[DocumentChunkWithScore] = [] + + # Extract Redis query + redis_query: RediSearchQuery = self._get_redis_query(query) + embedding = np.array(query.embedding, dtype=np.float64).tobytes() + + # Perform vector search + query_response = await self.client.ft(REDIS_INDEX_NAME).search( + redis_query, {"embedding": embedding} + ) + + # Iterate through the most similar documents + for doc in query_response.docs: + # Load JSON data + doc_json = json.loads(doc.json) + # Create document chunk object with score + result = DocumentChunkWithScore( + id=doc_json["metadata"]["document_id"], + score=doc.score, + text=doc_json["text"], + metadata=doc_json["metadata"] + ) + query_results.append(result) + + # Add to overall results + results.append(QueryResult(query=query.query, results=query_results)) + + return results + + async def _find_keys(self, pattern: str) -> List[str]: + return [key async for key in self.client.scan_iter(pattern)] + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + """ + Removes vectors by ids, filter, or everything in the datastore. + Returns whether the operation was successful. + """ + # Delete all vectors from the index if delete_all is True + if delete_all: + try: + logger.info(f"Deleting all documents from index") + await self.client.ft(REDIS_INDEX_NAME).dropindex(True) + logger.info(f"Deleted all documents successfully") + return True + except Exception as e: + logger.error(f"Error deleting all documents: {e}") + raise e + + # Delete by filter + if filter: + # TODO - extend this to work with other metadata filters? + if filter.document_id: + try: + keys = await self._find_keys( + f"{REDIS_DOC_PREFIX}:{filter.document_id}:*" + ) + await self._redis_delete(keys) + logger.info(f"Deleted document {filter.document_id} successfully") + except Exception as e: + logger.error(f"Error deleting document {filter.document_id}: {e}") + raise e + + # Delete by explicit ids (Redis keys) + if ids: + try: + logger.info(f"Deleting document ids {ids}") + keys = [] + # find all keys associated with the document ids + for document_id in ids: + doc_keys = await self._find_keys( + pattern=f"{REDIS_DOC_PREFIX}:{document_id}:*" + ) + keys.extend(doc_keys) + # delete all keys + logger.info(f"Deleting {len(keys)} keys from Redis") + await self._redis_delete(keys) + except Exception as e: + logger.error(f"Error deleting ids: {e}") + raise e + + return True diff --git a/datastore/providers/supabase_datastore.py b/datastore/providers/supabase_datastore.py new file mode 100644 index 000000000..ec7395e56 --- /dev/null +++ b/datastore/providers/supabase_datastore.py @@ -0,0 +1,95 @@ +import os +from typing import Any, List +from datetime import datetime + +from supabase import Client + +from datastore.providers.pgvector_datastore import PGClient, PgVectorDataStore +from models.models import ( + DocumentMetadataFilter, +) + +SUPABASE_URL = os.environ.get("SUPABASE_URL") +assert SUPABASE_URL is not None, "SUPABASE_URL is not set" +SUPABASE_ANON_KEY = os.environ.get("SUPABASE_ANON_KEY") +# use service role key if you want this app to be able to bypass your Row Level Security policies +SUPABASE_SERVICE_ROLE_KEY = os.environ.get("SUPABASE_SERVICE_ROLE_KEY") +assert ( + SUPABASE_ANON_KEY is not None or SUPABASE_SERVICE_ROLE_KEY is not None +), "SUPABASE_ANON_KEY or SUPABASE_SERVICE_ROLE_KEY must be set" + + +# class that implements the DataStore interface for Supabase Datastore provider +class SupabaseDataStore(PgVectorDataStore): + def create_db_client(self): + return SupabaseClient() + + +class SupabaseClient(PGClient): + def __init__(self) -> None: + super().__init__() + if not SUPABASE_SERVICE_ROLE_KEY: + self.client = Client(SUPABASE_URL, SUPABASE_ANON_KEY) + else: + self.client = Client(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY) + + async def upsert(self, table: str, json: dict[str, Any]): + """ + Takes in a list of documents and inserts them into the table. + """ + if "created_at" in json: + json["created_at"] = json["created_at"][0].isoformat() + + self.client.table(table).upsert(json).execute() + + async def rpc(self, function_name: str, params: dict[str, Any]): + """ + Calls a stored procedure in the database with the given parameters. + """ + if "in_start_date" in params: + params["in_start_date"] = params["in_start_date"].isoformat() + if "in_end_date" in params: + params["in_end_date"] = params["in_end_date"].isoformat() + + response = self.client.rpc(function_name, params=params).execute() + return response.data + + async def delete_like(self, table: str, column: str, pattern: str): + """ + Deletes rows in the table that match the pattern. + """ + self.client.table(table).delete().like(column, pattern).execute() + + async def delete_in(self, table: str, column: str, ids: List[str]): + """ + Deletes rows in the table that match the ids. + """ + self.client.table(table).delete().in_(column, ids).execute() + + async def delete_by_filters(self, table: str, filter: DocumentMetadataFilter): + """ + Deletes rows in the table that match the filter. + """ + builder = self.client.table(table).delete() + if filter.document_id: + builder = builder.eq( + "document_id", + filter.document_id, + ) + if filter.source: + builder = builder.eq("source", filter.source) + if filter.source_id: + builder = builder.eq("source_id", filter.source_id) + if filter.author: + builder = builder.eq("author", filter.author) + if filter.start_date: + builder = builder.gte( + "created_at", + filter.start_date[0].isoformat(), + ) + if filter.end_date: + builder = builder.lte( + "created_at", + filter.end_date[0].isoformat(), + ) + builder.execute() diff --git a/datastore/providers/weaviate_datastore.py b/datastore/providers/weaviate_datastore.py new file mode 100644 index 000000000..fe3ae3b56 --- /dev/null +++ b/datastore/providers/weaviate_datastore.py @@ -0,0 +1,385 @@ +import asyncio +import os +import re +import uuid +from typing import Dict, List, Optional + +import weaviate +from loguru import logger +from weaviate import Client +from weaviate.util import generate_uuid5 + +from datastore.datastore import DataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + DocumentChunkWithScore, + DocumentMetadataFilter, + QueryResult, + QueryWithEmbedding, + Source, +) + +WEAVIATE_URL_DEFAULT = "http://localhost:8080" +WEAVIATE_CLASS = os.environ.get("WEAVIATE_CLASS", "OpenAIDocument") + +WEAVIATE_BATCH_SIZE = int(os.environ.get("WEAVIATE_BATCH_SIZE", 20)) +WEAVIATE_BATCH_DYNAMIC = os.environ.get("WEAVIATE_BATCH_DYNAMIC", False) +WEAVIATE_BATCH_TIMEOUT_RETRIES = int(os.environ.get("WEAVIATE_TIMEOUT_RETRIES", 3)) +WEAVIATE_BATCH_NUM_WORKERS = int(os.environ.get("WEAVIATE_BATCH_NUM_WORKERS", 1)) + +SCHEMA = { + "class": WEAVIATE_CLASS, + "description": "The main class", + "properties": [ + { + "name": "chunk_id", + "dataType": ["string"], + "description": "The chunk id", + }, + { + "name": "document_id", + "dataType": ["string"], + "description": "The document id", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The chunk's text", + }, + { + "name": "source", + "dataType": ["string"], + "description": "The source of the data", + }, + { + "name": "source_id", + "dataType": ["string"], + "description": "The source id", + }, + { + "name": "url", + "dataType": ["string"], + "description": "The source url", + }, + { + "name": "created_at", + "dataType": ["date"], + "description": "Creation date of document", + }, + { + "name": "author", + "dataType": ["string"], + "description": "Document author", + }, + ], +} + + +def extract_schema_properties(schema): + properties = schema["properties"] + + return {property["name"] for property in properties} + + +class WeaviateDataStore(DataStore): + def handle_errors(self, results: Optional[List[dict]]) -> List[str]: + if not self or not results: + return [] + + error_messages = [] + for result in results: + if ( + "result" not in result + or "errors" not in result["result"] + or "error" not in result["result"]["errors"] + ): + continue + for message in result["result"]["errors"]["error"]: + error_messages.append(message["message"]) + logger.error(message["message"]) + + return error_messages + + def __init__(self): + auth_credentials = self._build_auth_credentials() + + url = os.environ.get("WEAVIATE_URL", WEAVIATE_URL_DEFAULT) + + logger.debug( + f"Connecting to weaviate instance at {url} with credential type {type(auth_credentials).__name__}" + ) + self.client = Client(url, auth_client_secret=auth_credentials) + self.client.batch.configure( + batch_size=WEAVIATE_BATCH_SIZE, + dynamic=WEAVIATE_BATCH_DYNAMIC, # type: ignore + callback=self.handle_errors, # type: ignore + timeout_retries=WEAVIATE_BATCH_TIMEOUT_RETRIES, + num_workers=WEAVIATE_BATCH_NUM_WORKERS, + ) + + if self.client.schema.contains(SCHEMA): + current_schema = self.client.schema.get(WEAVIATE_CLASS) + current_schema_properties = extract_schema_properties(current_schema) + + logger.debug( + f"Found index {WEAVIATE_CLASS} with properties {current_schema_properties}" + ) + logger.debug("Will reuse this schema") + else: + new_schema_properties = extract_schema_properties(SCHEMA) + logger.debug( + f"Creating collection {WEAVIATE_CLASS} with properties {new_schema_properties}" + ) + self.client.schema.create_class(SCHEMA) + + @staticmethod + def _build_auth_credentials(): + url = os.environ.get("WEAVIATE_URL", WEAVIATE_URL_DEFAULT) + + if WeaviateDataStore._is_wcs_domain(url): + api_key = os.environ.get("WEAVIATE_API_KEY") + if api_key is not None: + return weaviate.auth.AuthApiKey(api_key=api_key) + else: + raise ValueError("WEAVIATE_API_KEY environment variable is not set") + else: + return None + + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: + """ + Takes in a list of list of document chunks and inserts them into the database. + Return a list of document ids. + """ + doc_ids = [] + + with self.client.batch as batch: + for doc_id, doc_chunks in chunks.items(): + logger.debug(f"Upserting {doc_id} with {len(doc_chunks)} chunks") + for doc_chunk in doc_chunks: + # we generate a uuid regardless of the format of the document_id because + # weaviate needs a uuid to store each document chunk and + # a document chunk cannot share the same uuid + doc_uuid = generate_uuid5(doc_chunk, WEAVIATE_CLASS) + metadata = doc_chunk.metadata + doc_chunk_dict = doc_chunk.dict() + doc_chunk_dict.pop("metadata") + for key, value in metadata.dict().items(): + doc_chunk_dict[key] = value + doc_chunk_dict["chunk_id"] = doc_chunk_dict.pop("id") + doc_chunk_dict["source"] = ( + doc_chunk_dict.pop("source").value + if doc_chunk_dict["source"] + else None + ) + embedding = doc_chunk_dict.pop("embedding") + + batch.add_data_object( + uuid=doc_uuid, + data_object=doc_chunk_dict, + class_name=WEAVIATE_CLASS, + vector=embedding, + ) + + doc_ids.append(doc_id) + batch.flush() + return doc_ids + + async def _query( + self, + queries: List[QueryWithEmbedding], + ) -> List[QueryResult]: + """ + Takes in a list of queries with embeddings and filters and returns a list of query results with matching document chunks and scores. + """ + + async def _single_query(query: QueryWithEmbedding) -> QueryResult: + logger.debug(f"Query: {query.query}") + if not hasattr(query, "filter") or not query.filter: + result = ( + self.client.query.get( + WEAVIATE_CLASS, + [ + "chunk_id", + "document_id", + "text", + "source", + "source_id", + "url", + "created_at", + "author", + ], + ) + .with_hybrid(query=query.query, alpha=0.5, vector=query.embedding) + .with_limit(query.top_k) # type: ignore + .with_additional(["score", "vector"]) + .do() + ) + else: + filters_ = self.build_filters(query.filter) + result = ( + self.client.query.get( + WEAVIATE_CLASS, + [ + "chunk_id", + "document_id", + "text", + "source", + "source_id", + "url", + "created_at", + "author", + ], + ) + .with_hybrid(query=query.query, alpha=0.5, vector=query.embedding) + .with_where(filters_) + .with_limit(query.top_k) # type: ignore + .with_additional(["score", "vector"]) + .do() + ) + + query_results: List[DocumentChunkWithScore] = [] + response = result["data"]["Get"][WEAVIATE_CLASS] + + for resp in response: + result = DocumentChunkWithScore( + id=resp["chunk_id"], + text=resp["text"], + # embedding=resp["_additional"]["vector"], + score=resp["_additional"]["score"], + metadata=DocumentChunkMetadata( + document_id=resp["document_id"] if resp["document_id"] else "", + source=Source(resp["source"]) if resp["source"] else None, + source_id=resp["source_id"], + url=resp["url"], + created_at=resp["created_at"], + author=resp["author"], + ), + ) + query_results.append(result) + return QueryResult(query=query.query, results=query_results) + + return await asyncio.gather(*[_single_query(query) for query in queries]) + + async def delete( + self, + ids: Optional[List[str]] = None, + filter: Optional[DocumentMetadataFilter] = None, + delete_all: Optional[bool] = None, + ) -> bool: + # TODO + """ + Removes vectors by ids, filter, or everything in the datastore. + Returns whether the operation was successful. + """ + if delete_all: + logger.debug(f"Deleting all vectors in index {WEAVIATE_CLASS}") + self.client.schema.delete_all() + return True + + if ids: + operands = [ + {"path": ["document_id"], "operator": "Equal", "valueString": id} + for id in ids + ] + + where_clause = {"operator": "Or", "operands": operands} + + logger.debug(f"Deleting vectors from index {WEAVIATE_CLASS} with ids {ids}") + result = self.client.batch.delete_objects( + class_name=WEAVIATE_CLASS, where=where_clause, output="verbose" + ) + + if not bool(result["results"]["successful"]): + logger.debug( + f"Failed to delete the following objects: {result['results']['objects']}" + ) + + if filter: + where_clause = self.build_filters(filter) + + logger.debug( + f"Deleting vectors from index {WEAVIATE_CLASS} with filter {where_clause}" + ) + result = self.client.batch.delete_objects( + class_name=WEAVIATE_CLASS, where=where_clause + ) + + if not bool(result["results"]["successful"]): + logger.debug( + f"Failed to delete the following objects: {result['results']['objects']}" + ) + + return True + + @staticmethod + def build_filters(filter): + if filter.source: + filter.source = filter.source.value + + operands = [] + filter_conditions = { + "source": { + "operator": "Equal", + "value": "query.filter.source.value", + "value_key": "valueString", + }, + "start_date": {"operator": "GreaterThanEqual", "value_key": "valueDate"}, + "end_date": {"operator": "LessThanEqual", "value_key": "valueDate"}, + "default": {"operator": "Equal", "value_key": "valueString"}, + } + + for attr, value in filter.__dict__.items(): + if value is not None: + filter_condition = filter_conditions.get( + attr, filter_conditions["default"] + ) + value_key = filter_condition["value_key"] + + operand = { + "path": [ + attr + if not (attr == "start_date" or attr == "end_date") + else "created_at" + ], + "operator": filter_condition["operator"], + value_key: value, + } + + operands.append(operand) + + return {"operator": "And", "operands": operands} + + @staticmethod + def _is_valid_weaviate_id(candidate_id: str) -> bool: + """ + Check if candidate_id is a valid UUID for weaviate's use + + Weaviate supports UUIDs of version 3, 4 and 5. This function checks if the candidate_id is a valid UUID of one of these versions. + See https://weaviate.io/developers/weaviate/more-resources/faq#q-are-there-restrictions-on-uuid-formatting-do-i-have-to-adhere-to-any-standards + for more information. + """ + acceptable_version = [3, 4, 5] + + try: + result = uuid.UUID(candidate_id) + if result.version not in acceptable_version: + return False + else: + return True + except ValueError: + return False + + @staticmethod + def _is_wcs_domain(url: str) -> bool: + """ + Check if the given URL ends with ".weaviate.network" or ".weaviate.network/". + + Args: + url (str): The URL to check. + + Returns: + bool: True if the URL ends with the specified strings, False otherwise. + """ + pattern = r"\.(weaviate\.cloud|weaviate\.network)(/)?$" + return bool(re.search(pattern, url)) diff --git a/datastore/providers/zilliz_datastore.py b/datastore/providers/zilliz_datastore.py new file mode 100644 index 000000000..81f151c43 --- /dev/null +++ b/datastore/providers/zilliz_datastore.py @@ -0,0 +1,65 @@ +import os + +from loguru import logger +from typing import Optional +from pymilvus import ( + connections, +) +from uuid import uuid4 + +from datastore.providers.milvus_datastore import ( + MilvusDataStore, +) + + +ZILLIZ_COLLECTION = os.environ.get("ZILLIZ_COLLECTION") or "c" + uuid4().hex +ZILLIZ_URI = os.environ.get("ZILLIZ_URI") +ZILLIZ_USER = os.environ.get("ZILLIZ_USER") +ZILLIZ_PASSWORD = os.environ.get("ZILLIZ_PASSWORD") +ZILLIZ_USE_SECURITY = False if ZILLIZ_PASSWORD is None else True + +ZILLIZ_CONSISTENCY_LEVEL = os.environ.get("ZILLIZ_CONSISTENCY_LEVEL") + +class ZillizDataStore(MilvusDataStore): + def __init__(self, create_new: Optional[bool] = False): + """Create a Zilliz DataStore. + + The Zilliz Datastore allows for storing your indexes and metadata within a Zilliz Cloud instance. + + Args: + create_new (Optional[bool], optional): Whether to overwrite if collection already exists. Defaults to True. + """ + # Overwrite the default consistency level by MILVUS_CONSISTENCY_LEVEL + self._consistency_level = ZILLIZ_CONSISTENCY_LEVEL or "Bounded" + self._create_connection() + + self._create_collection(ZILLIZ_COLLECTION, create_new) # type: ignore + self._create_index() + + def _create_connection(self): + # Check if the connection already exists + try: + i = [ + connections.get_connection_addr(x[0]) + for x in connections.list_connections() + ].index({"address": ZILLIZ_URI, "user": ZILLIZ_USER}) + self.alias = connections.list_connections()[i][0] + except ValueError: + # Connect to the Zilliz instance using the passed in Environment variables + self.alias = uuid4().hex + connections.connect(alias=self.alias, uri=ZILLIZ_URI, user=ZILLIZ_USER, password=ZILLIZ_PASSWORD, secure=ZILLIZ_USE_SECURITY) # type: ignore + logger.info("Connect to zilliz cloud server") + + def _create_index(self): + try: + # If no index on the collection, create one + if len(self.col.indexes) == 0: + self.index_params = {"metric_type": "IP", "index_type": "AUTOINDEX", "params": {}} + self.col.create_index("embedding", index_params=self.index_params) + + self.col.load() + self.search_params = {"metric_type": "IP", "params": {}} + except Exception as e: + logger.error("Failed to create index, error: {}".format(e)) + + diff --git a/docs/deployment/flyio.md b/docs/deployment/flyio.md new file mode 100644 index 000000000..17cf55bb9 --- /dev/null +++ b/docs/deployment/flyio.md @@ -0,0 +1,89 @@ +# Deploying to Fly.io + +## Removing Unused Dependencies + +Before deploying your app, you might want to remove unused dependencies from your [pyproject.toml](/pyproject.toml) file to reduce the size of your app and improve its performance. Depending on the vector database provider you choose, you can remove the packages that are not needed for your specific provider. + +Find the packages you can remove for each vector database provider [here](removing-unused-dependencies.md). + +After removing the unnecessary packages from the `pyproject.toml` file, you don't need to run `poetry lock` and `poetry install` manually. The provided Dockerfile takes care of installing the required dependencies using the `requirements.txt` file generated by the `poetry export` command. + +## Deployment + +To deploy the Docker container from this repository to Fly.io, follow +these steps: + +[Install Docker](https://docs.docker.com/engine/install/) on your local machine if it is not already installed. + +Install the [Fly.io CLI](https://fly.io/docs/getting-started/installing-flyctl/) on your local machine. + +Clone the repository from GitHub: + +``` +git clone https://github.com/openai/chatgpt-retrieval-plugin.git +``` + +Navigate to the cloned repository directory: + +``` +cd path/to/chatgpt-retrieval-plugin +``` + +Log in to the Fly.io CLI: + +``` +flyctl auth login +``` + +Create and launch your Fly.io app: + +``` +flyctl launch +``` + +Follow the instructions in your terminal: + +- Choose your app name +- Choose your app region +- Don't add any databases +- Don't deploy yet (if you do, the first deploy might fail as the environment variables are not yet set) + +Set the required environment variables: + +``` +flyctl secrets set DATASTORE=your_datastore \ +OPENAI_API_KEY=your_openai_api_key \ +BEARER_TOKEN=your_bearer_token \ + +``` + +Alternatively, you could set environment variables in the [Fly.io Console](https://fly.io/dashboard). + +At this point, you can change the plugin url in your plugin manifest file [here](/.well-known/ai-plugin.json), and in your OpenAPI schema [here](/.well-known/openapi.yaml) to the url for your Fly.io app, which will be `https://your-app-name.fly.dev`. + +Deploy your app with: + +``` +flyctl deploy +``` + +After completing these steps, your Docker container should be deployed to Fly.io and running with the necessary environment variables set. You can view your app by running: + +``` +flyctl open +``` + +which will open your app url. You should be able to find the OpenAPI schema at `/.well-known/openapi.yaml` and the manifest at `/.well-known/ai-plugin.json`. + +To view your app logs: + +``` +flyctl logs +``` + +Now, make sure you have changed the plugin url in your plugin manifest file [here](/.well-known/ai-plugin.json), and in your OpenAPI schema [here](/.well-known/openapi.yaml), and redeploy with `flyctl deploy`. This url will be `https://.fly.dev`. + +**Debugging tips:** +Fly.io uses port 8080 by default. + +If your app fails to deploy, check if the environment variables are set correctly, and then check if your port is configured correctly. You could also try using the [`-e` flag](https://fly.io/docs/flyctl/launch/) with the `flyctl launch` command to set the environment variables at launch. diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md new file mode 100644 index 000000000..1323bf4f7 --- /dev/null +++ b/docs/deployment/heroku.md @@ -0,0 +1,105 @@ +# Deploying to Heroku + +## Removing Unused Dependencies + +Before deploying your app, you might want to remove unused dependencies from your [pyproject.toml](/pyproject.toml) file to reduce the size of your app and improve its performance. Depending on the vector database provider you choose, you can remove the packages that are not needed for your specific provider. + +Find the packages you can remove for each vector database provider [here](removing-unused-dependencies.md). + +After removing the unnecessary packages from the `pyproject.toml` file, you don't need to run `poetry lock` and `poetry install` manually. The provided Dockerfile takes care of installing the required dependencies using the `requirements.txt` file generated by the `poetry export` command. + +## Deployment + +To deploy the Docker container from this repository to Heroku and set the required environment variables, follow these steps: + +[Install Docker](https://docs.docker.com/engine/install/) on your local machine if it is not already installed. + +Install the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) on your local machine. + +Clone the repository from GitHub: + +``` +git clone https://github.com/openai/chatgpt-retrieval-plugin.git +``` + +Navigate to the cloned repository directory: + +``` +cd path/to/chatgpt-retrieval-plugin +``` + +Log in to the Heroku CLI: + +``` +heroku login +``` + +Create a Heroku app: + +``` +heroku create [app-name] +``` + +Log in to the Heroku Container Registry: + +``` +heroku container:login +``` + +Alternatively, you can use a command from the Makefile to log in to the Heroku Container Registry by running: + +``` +make heroku-login +``` + +Build the Docker image using the Dockerfile: + +``` +docker buildx build --platform linux/amd64 -t [image-name] . +``` + +(Replace `[image-name]` with the name you want to give your Docker image) + +Push the Docker image to the Heroku Container Registry, and release the newly pushed image to your Heroku app. + +``` +docker tag [image-name] registry.heroku.com/[app-name]/web +docker push registry.heroku.com/[app-name]/web +heroku container:release web -a [app-name] +``` + +Alternatively, you can use a command from the to push the Docker image to the Heroku Container Registry by running: + +``` +make heroku-push +``` + +**Note:** You will need to edit the Makefile and replace `` with your actual app name. + +Set the required environment variables for your Heroku app: + +``` +heroku config:set DATASTORE=your_datastore \ +OPENAI_API_KEY=your_openai_api_key \ +BEARER_TOKEN=your_bearer_token \ + \ +-a [app-name] +``` + +You could also set environment variables in the [Heroku Console](https://dashboard.heroku.com/apps). + +After completing these steps, your Docker container should be deployed to Heroku and running with the necessary environment variables set. You can view your app by running: + +``` +heroku open -a [app-name] +``` + +which will open your app url. You should be able to find the OpenAPI schema at `/.well-known/openapi.yaml` and the manifest at `/.well-known/ai-plugin.json`. + +To view your app logs: + +``` +heroku logs --tail -a [app-name] +``` + +Now make sure to change the plugin url in your plugin manifest file [here](/.well-known/ai-plugin.json), and in your OpenAPI schema [here](/.well-known/openapi.yaml), and redeploy with `make heroku-push`. This url will be `https://your-app-name.herokuapp.com`. diff --git a/docs/deployment/other-options.md b/docs/deployment/other-options.md new file mode 100644 index 000000000..6f4a697f6 --- /dev/null +++ b/docs/deployment/other-options.md @@ -0,0 +1,17 @@ +# Other Deployment Options + +Some possible other options for deploying the app are: + +- **Azure Container Apps**: This is a cloud platform that allows you to deploy and manage web apps using Docker containers. You can use the Azure CLI or the Azure Portal to create and configure your app service, and then push your Docker image to a container registry and deploy it to your app service. You can also set environment variables and scale your app using the Azure Portal. Learn more [here](https://learn.microsoft.com/en-us/azure/container-apps/get-started-existing-container-image-portal?pivots=container-apps-private-registry). +- **Google Cloud Run**: This is a serverless platform that allows you to run stateless web apps using Docker containers. You can use the Google Cloud Console or the gcloud command-line tool to create and deploy your Cloud Run service, and then push your Docker image to the Google Container Registry and deploy it to your service. You can also set environment variables and scale your app using the Google Cloud Console. Learn more [here](https://cloud.google.com/run/docs/quickstarts/build-and-deploy). +- **AWS Elastic Container Service**: This is a cloud platform that allows you to run and manage web apps using Docker containers. You can use the AWS CLI or the AWS Management Console to create and configure your ECS cluster, and then push your Docker image to the Amazon Elastic Container Registry and deploy it to your cluster. You can also set environment variables and scale your app using the AWS Management Console. Learn more [here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html). + +After you create your app, make sure to change the plugin url in your plugin manifest file [here](/.well-known/ai-plugin.json), and in your OpenAPI schema [here](/.well-known/openapi.yaml), and redeploy. + +## Removing Unused Dependencies + +Before deploying your app, you might want to remove unused dependencies from your [pyproject.toml](/pyproject.toml) file to reduce the size of your app and improve its performance. Depending on the vector database provider you choose, you can remove the packages that are not needed for your specific provider. + +Find the packages you can remove for each vector database provider [here](removing_unused_dependencies.md). + +After removing the unnecessary packages from the `pyproject.toml` file, you don't need to run `poetry lock` and `poetry install` manually. The provided Dockerfile takes care of installing the required dependencies using the `requirements.txt` file generated by the `poetry export` command. diff --git a/docs/deployment/removing-unused-dependencies.md b/docs/deployment/removing-unused-dependencies.md new file mode 100644 index 000000000..44a56c630 --- /dev/null +++ b/docs/deployment/removing-unused-dependencies.md @@ -0,0 +1,20 @@ +# Removing Unused Dependencies + +Before deploying your app, you might want to remove unused dependencies from your [pyproject.toml](/pyproject.toml) file to reduce the size of your app and improve its performance. Depending on the vector database provider you choose, you can remove the packages that are not needed for your specific provider. + +Here are the packages you can remove for each vector database provider: + +- **Pinecone:** Remove `weaviate-client`, `pymilvus`, `qdrant-client`, `redis`, `chromadb`, `llama-index`, `azure-identity`, `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Weaviate:** Remove `pinecone-client`, `pymilvus`, `qdrant-client`, `redis`, `chromadb`, `llama-index`, `azure-identity` and `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, `psycopg2cffi`. +- **Zilliz:** Remove `pinecone-client`, `weaviate-client`, `qdrant-client`, `redis`, `chromadb`, `llama-index`, `azure-identity` and `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Milvus:** Remove `pinecone-client`, `weaviate-client`, `qdrant-client`, `redis`, `chromadb`, `llama-index`, `azure-identity` and `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Qdrant:** Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `redis`, `chromadb`, `llama-index`, `azure-identity` and `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Redis:** Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `qdrant-client`, `chromadb`, `llama-index`, `azure-identity` and `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **LlamaIndex:** Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `qdrant-client`, `chromadb`, `redis`, `azure-identity` and `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Chroma:**: Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `qdrant-client`, `llama-index`, `redis`, `azure-identity` and `azure-search-documents`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Azure Cognitive Search**: Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `qdrant-client`, `llama-index`, `redis` and `chromadb`, `supabase`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Supabase:** Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `qdrant-client`, `redis`, `llama-index`, `azure-identity` and `azure-search-documents`, `psycopg2`+`pgvector`, and `psycopg2cffi`. +- **Postgres:** Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `qdrant-client`, `redis`, `llama-index`, `azure-identity` and `azure-search-documents`, `supabase`, and `psycopg2cffi`. +- **AnalyticDB:** Remove `pinecone-client`, `weaviate-client`, `pymilvus`, `qdrant-client`, `redis`, `llama-index`, `azure-identity` and `azure-search-documents`, `supabase`, and `psycopg2`+`pgvector`. + +After removing the unnecessary packages from the `pyproject.toml` file, you don't need to run `poetry lock` and `poetry install` manually. The provided Dockerfile takes care of installing the required dependencies using the `requirements.txt` file generated by the `poetry export` command. diff --git a/docs/deployment/render-thumbnail.png b/docs/deployment/render-thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..4bd725aaeffa399af7d2302f0529e7420889380e GIT binary patch literal 260172 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%0D?ZJZ{0&sVuHLo}e}(gVdg0h6b=f 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

KY`tV^3x4}jA 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 kw@BkC`QkR*H$bf&!O6s@rZxc~qF literal 0 HcmV?d00001 diff --git a/docs/deployment/render.md b/docs/deployment/render.md new file mode 100644 index 000000000..741f55538 --- /dev/null +++ b/docs/deployment/render.md @@ -0,0 +1,19 @@ +# Deploying to Render + +## Removing Unused Dependencies + +Before deploying your app, you might want to remove unused dependencies from your [pyproject.toml](/pyproject.toml) file to reduce the size of your app and improve its performance. Depending on the vector database provider you choose, you can remove the packages that are not needed for your specific provider. + +Find the packages you can remove for each vector database provider [here](removing-unused-dependencies.md). + +After removing the unnecessary packages from the `pyproject.toml` file, you don't need to run `poetry lock` and `poetry install` manually. The provided Dockerfile takes care of installing the required dependencies using the `requirements.txt` file generated by the `poetry export` command. + +## Deployment + +Render maintains a [fork](https://github.com/render-examples/chatgpt-retrieval-plugin/) of this repository with a few small changes that facilitate easy deployment. The source code is unchanged. To deploy both the Docker container from this repository and a self-hosted Weaviate database to back it, just click the button below. Enter your OpenAI API key when prompted. + +[Deploy to Render](https://render.com/deploy?repo=https://github.com/render-examples/chatgpt-retrieval-plugin/tree/main) + +The bearer token will be randomly generated for you. You can view it in in the "Environment" tab on the [Render dashboard](https://dashboard.render.com) page for your server. For more guidance, consult the [README in Render's fork](https://github.com/render-examples/chatgpt-retrieval-plugin/blob/main/README.md), [Render's documentation](https://render.com/docs), or the screen recording linked below. + +[![Deploy to Render screen recording](render-thumbnail.png)](https://vimeo.com/823610578) diff --git a/docs/providers/analyticdb/setup.md b/docs/providers/analyticdb/setup.md new file mode 100644 index 000000000..8aed01f44 --- /dev/null +++ b/docs/providers/analyticdb/setup.md @@ -0,0 +1,82 @@ +# AnalyticDB + +[AnalyticDB](https://www.alibabacloud.com/help/en/analyticdb-for-postgresql/latest/product-introduction-overview) is a distributed cloud-native vector database designed for storing documents and vector embeddings. It is a high-performance vector database that is fully compatible with PostgreSQL syntax, making it easy to use. Managed by Alibaba Cloud, AnalyticDB offers a powerful vector compute engine, processing billions of data vectors and providing a wide range of features, including indexing algorithms, structured and unstructured data capabilities, real-time updates, distance metrics, scalar filtering, and time travel searches. Additionally, it offers full OLAP database functionality and an SLA commitment for production use. + +## Install Requirements + +Run the following command to install the required packages, including the `psycopg2cffi` package: + +``` +poetry install --extras "postgresql" +``` + +If you encounter the `Error: pg_config executable not found.` issue, you need to install the PostgreSQL development package on your system. Follow the instructions for your specific Linux distribution: + +1. Debian-based systems (e.g., Ubuntu): + +```bash +sudo apt-get update +sudo apt-get install libpq-dev +``` + +2. RHEL-based systems (e.g., CentOS, Fedora): + +```bash +sudo yum install postgresql-devel +``` + +3. Arch-based systems (e.g., Manjaro, Arch Linux): + +```bash +sudo pacman -S postgresql-libs +``` + +4. macOS: + +```bash +brew install postgresql +``` + +After installing the required package, try to install `psycopg2cffi` again. If the `pg_config` executable is still not found, add its location to your system's `PATH` variable. You can typically find the `pg_config` executable in the `bin` directory of your PostgreSQL installation, for example `/usr/pgsql-13/bin/pg_config`. To add it to your `PATH` variable, use the following command (replace the path with the correct one for your system): + +```bash +export PATH=$PATH:/usr/pgsql-13/bin +``` + +Now, try installing `psycopg2cffi` again using Poetry. + +**Environment Variables:** + +| Name | Required | Description | Default | +| ---------------- | -------- | ----------------------------------- | ----------------- | +| `DATASTORE` | Yes | Datastore name, set to `analyticdb` | | +| `BEARER_TOKEN` | Yes | Secret token | | +| `OPENAI_API_KEY` | Yes | OpenAI API key | | +| `PG_HOST` | Yes | AnalyticDB instance URL | `localhost` | +| `PG_USER` | Yes | Database user | `user` | +| `PG_PASSWORD` | Yes | Database password | `password` | +| `PG_PORT` | Optional | Port for AnalyticDB communication | `5432` | +| `PG_DATABASE` | Optional | Database name | `postgres` | +| `PG_COLLECTION` | Optional | AnalyticDB relation name | `document_chunks` | + +## AnalyticDB Cloud + +For a hosted [AnalyticDB Cloud](https://cloud.qdrant.io/) version, provide the AnalyticDB instance URL: + +**Example:** + +```bash +PG_HOST="https://YOUR-CLUSTER-URL.gpdb.rds.aliyuncs.com" +PG_USER="YOUR-USER-NAME" +PG_PASSWORD="YOUR-PASSWORD" +``` + +The other parameters are optional and can be changed if needed. + +## Running AnalyticDB Integration Tests + +A suite of integration tests verifies the AnalyticDB integration. Launch the test suite with this command: + +```bash +pytest ./tests/datastore/providers/analyticdb/test_analyticdb_datastore.py +``` diff --git a/docs/providers/azuresearch/setup.md b/docs/providers/azuresearch/setup.md new file mode 100644 index 000000000..e184c2621 --- /dev/null +++ b/docs/providers/azuresearch/setup.md @@ -0,0 +1,29 @@ +# Azure Cognitive Search + +[Azure Cognitive Search](https://azure.microsoft.com/products/search/) is a complete retrieval cloud service that supports vector search, text search, and hybrid (vectors + text combined to yield the best of the two approaches). Azure Cognitive Search also offers an [optional L2 re-ranking step](https://learn.microsoft.com/azure/search/semantic-search-overview) to further improve results quality. + +You can find the Azure Cognitive Search documentation [here](https://learn.microsoft.com/azure/search/search-what-is-azure-search). If you don't have an Azure account, you can start setting one up [here](https://azure.microsoft.com/). + +## Environment variables + +| Name | Required | Description | Default | +| ---------------------------- | -------- | ------------------------------------------------------------------------------------- | ------------------- | +| `DATASTORE` | Yes | Datastore name, set to `azuresearch` | | +| `BEARER_TOKEN` | Yes | Secret token | | +| `OPENAI_API_KEY` | Yes | OpenAI API key | | +| `AZURESEARCH_SERVICE` | Yes | Name of your search service | | +| `AZURESEARCH_INDEX` | Yes | Name of your search index | | +| `AZURESEARCH_API_KEY` | No | Your API key, if using key-based auth instead of Azure managed identity |Uses managed identity| +| `AZURESEARCH_DISABLE_HYBRID` | No | Disable hybrid search and only use vector similarity |Use hybrid search | +| `AZURESEARCH_SEMANTIC_CONFIG`| No | Enable L2 re-ranking with this configuration name [see re-ranking below](#re-ranking) |L2 not enabled | +| `AZURESEARCH_LANGUAGE` | No | If using L2 re-ranking, language for queries/documents (valid values [listed here](https://learn.microsoft.com/rest/api/searchservice/preview-api/search-documents#queryLanguage)) |`en-us` | +| `AZURESEARCH_DIMENSIONS` | No | Vector size for embeddings |1536 (OpenAI's Ada002)| + +## Authentication Options + +* API key: this is enabled by default; you can obtain the key in the Azure Portal or using the Azure CLI. +* Managed identity: If the plugin is running in Azure, you can enable managed identity for the host and give that identity access to the service, without having to manage keys (avoiding secret storage, rotation, etc.). More details [here](https://learn.microsoft.com/azure/search/search-security-rbac). + +## Re-ranking + +Azure Cognitive Search offers the option to enable a second (L2) ranking step after retrieval to further improve results quality. This only applies when using text or hybrid search. Since it has latency and cost implications, if you want to try this option you need to explicitly [enable "semantic search"](https://learn.microsoft.com/azure/search/semantic-search-overview#enable-semantic-search) in your Cognitive Search service, and [create a semantic search configuration](https://learn.microsoft.com/azure/search/semantic-how-to-query-request#2---create-a-semantic-configuration) for your index. \ No newline at end of file diff --git a/docs/providers/chroma/setup.md b/docs/providers/chroma/setup.md new file mode 100644 index 000000000..2822b0454 --- /dev/null +++ b/docs/providers/chroma/setup.md @@ -0,0 +1,29 @@ +[Chroma](https://trychroma.com) is an AI-native open-source embedding database designed to make it easy to work with embeddings. Chroma runs in-memory, or in a client-server setup. + +Install Chroma by running `pip install chromadb`. Once installed, the core API consists of four essential commands for creating collections, adding embeddings, documents, and metadata, and querying embeddings to find similar documents. Get started with Chroma by visiting the [Getting Started](https://docs.trychroma.com) page on their documentation website, or explore the open-source code on their [GitHub repository](https://github.com/chroma-core/chroma). + +**Chroma Environment Variables** + +To set up Chroma and start using it as your vector database provider, you need to define some environment variables to connect to your Chroma instance. + +**Chroma Datastore Environment Variables** + +Chroma runs _in-memory_ by default, with local persistence. It can also run in [self-hosted](https://docs.trychroma.com/usage-guide#running-chroma-in-clientserver-mode) client-server mode, with a fully managed hosted version coming soon. + +| Name | Required | Description | Default | +| ------------------------ | -------- | -------------------------------------------------------------------------------------------------- | ---------------- | +| `DATASTORE` | Yes | Datastore name. Set this to `chroma` | | +| `BEARER_TOKEN` | Yes | Your secret token for authenticating requests to the API | | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key for generating embeddings | | +| `CHROMA_COLLECTION` | Optional | Your chosen Chroma collection name to store your embeddings | openaiembeddings | +| `CHROMA_IN_MEMORY` | Optional | If set to `True`, ignore `CHROMA_HOST` and `CHROMA_PORT` and just use an in-memory Chroma instance | `True` | +| `CHROMA_PERSISTENCE_DIR` | Optional | If set, and `CHROMA_IN_MEMORY` is set, persist to and load from this directory. | `openai` | + +To run Chroma in self-hosted client-server mode, st the following variables: + +| Name | Required | Description | Default | +| ------------- | -------- | --------------------------------------------------- | ------------------ | +| `CHROMA_HOST` | Optional | Your Chroma instance host address (see notes below) | `http://127.0.0.1` | +| `CHROMA_PORT` | Optional | Your Chroma port number | `8000` | + +> For **self-hosted instances**, if your instance is not at 127.0.0.1:8000, set `CHROMA_HOST` and `CHROMA_PORT` accordingly. For example: `CHROMA_HOST=http://localhost/` and `CHROMA_PORT=8080`. diff --git a/docs/providers/elasticsearch/setup.md b/docs/providers/elasticsearch/setup.md new file mode 100644 index 000000000..9a3d5ea12 --- /dev/null +++ b/docs/providers/elasticsearch/setup.md @@ -0,0 +1,37 @@ +# Elasticsearch + +Elasticsearch is a search engine based on the Lucene library. It provides a distributed, full-text and vector search engine with an HTTP web interface and schema-free JSON documents. To use Elasticsearch as your vector database, start by [installing Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html) or signing up for a free trial of [Elastic Cloud](https://www.elastic.co/cloud/). + +The app will create an Elasticsearch index for you automatically when you run it for the first time. Just pick a name for your index and set it as an environment variable. + +**Environment Variables:** + +| Name | Required | Description | +| --------------------- | -------- | -------------------------------------------------------------------------------------------------------------------- | +| `DATASTORE` | Yes | Datastore name, set this to `elasticsearch` | +| `BEARER_TOKEN` | Yes | Your secret token for authenticating requests to the API | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key for generating embeddings with the `text-embedding-ada-002` model | +| `ELASTICSEARCH_INDEX` | Yes | Your chosen Elasticsearch index name. **Note:** Index name must consist of lower case alphanumeric characters or '-' | + +**Connection Evironment Variables:** +Depending on your Elasticsearch setup, you may need to set one of the following environment variables to connect to your Elasticsearch instance. If you are using Elastic Cloud, you can connect via `ELASTICSEARCH_CLOUD_ID`. If you are using a local instance of Elasticsearch, you will need to set `ELASTICSEARCH_URL`. + +You can authenticate to Elasticsearch using either `ELASTICSEARCH_USERNAME` and `ELASTICSEARCH_PASSWORD` or `ELASTICSEARCH_API_KEY`. If you are using Elastic Cloud, you can find this in Kibana. + +| Name | Required | Description | +| ------------------------ | -------- | ------------------------------------------------------------------------------------------------ | +| `ELASTICSEARCH_URL` | Yes | Your Elasticsearch URL. If installed locally, this would be https://localhost:9200 | +| `ELASTICSEARCH_CLOUD_ID` | Yes | Your cloud id, linked to your deployment. This can be found in the deployment's console | +| `ELASTICSEARCH_USERNAME` | Yes | Your username for authenticating requests to the API. Commonly 'elastic'. | +| `ELASTICSEARCH_PASSWORD` | Yes | Your password for authenticating requests to the API | +| `ELASTICSEARCH_API_KEY` | Yes | Alternatively you can authenticate using api-key. This can be created in Kibana stack management | + +## Running Elasticsearch Integration Tests + +A suite of integration tests is available to verify the Elasticsearch integration. To run the tests, run the docker compose found in the `examples/docker/elasticsearch` folder with `docker-compose up`. This will start Elasticsearch in single node, security off mode, listening on `http://localhost:9200`. + +Then, launch the test suite with this command: + +```bash +pytest ./tests/datastore/providers/elasticsearch/test_elasticsearch_datastore.py +``` diff --git a/docs/providers/llama/setup.md b/docs/providers/llama/setup.md new file mode 100644 index 000000000..2378700dd --- /dev/null +++ b/docs/providers/llama/setup.md @@ -0,0 +1,51 @@ + +# LlamaIndex + +[LlamaIndex](https://github.com/jerryjliu/llama_index) is a central interface to connect your LLM's with external data. +It provides a suite of in-memory indices over your unstructured and structured data for use with ChatGPT. +Unlike standard vector databases, LlamaIndex supports a wide range of indexing strategies (e.g. tree, keyword table, knowledge graph) optimized for different use-cases. +It is light-weight, easy-to-use, and requires no additional deployment. +All you need to do is specifying a few environment variables (optionally point to an existing saved Index json file). +Note that metadata filters in queries are not yet supported. + +## Setup +Currently, LlamaIndex requires no additional deployment +and runs as a part of the Retrieval Plugin. +It is super easy to setup and great for quick prototyping +with ChatGPT and your external data. + +**Retrieval App Environment Variables** + +| Name | Required | Description | +|------------------|----------|-------------------------------------| +| `DATASTORE` | Yes | Datastore name. Set this to `llama` | +| `BEARER_TOKEN` | Yes | Your secret token | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key | + +**Llama Datastore Environment Variables** + +| Name | Required | Description | Default | +|--------------------------------|----------|--------------------------------------|---------------| +| `LLAMA_INDEX_TYPE` | Optional | Index type (see below for details) | `simple_dict` | +| `LLAMA_INDEX_JSON_PATH` | Optional | Path to saved Index json file | None | +| `LLAMA_QUERY_KWARGS_JSON_PATH` | Optional | Path to saved query kwargs json file | None | +| `LLAMA_RESPONSE_MODE` | Optional | Response mode for query | `no_text` | + + +**Different Index Types** +By default, we use a `GPTSimpleVectorIndex` to store document chunks in memory, +and retrieve top-k nodes by embedding similarity. +Different index types are optimized for different data and query use-cases. +See this guide on [How Each Index Works](https://gpt-index.readthedocs.io/en/latest/guides/primer/index_guide.html) to learn more. +You can configure the index type via the `LLAMA_INDEX_TYPE`, see [here](https://gpt-index.readthedocs.io/en/latest/reference/indices/composability_query.html#gpt_index.data_structs.struct_type.IndexStructType) for the full list of accepted index type identifiers. + + +Read more details on [readthedocs](https://gpt-index.readthedocs.io/en/latest/), +and engage with the community on [discord](https://discord.com/invite/dGcwcsnxhU). + +## Running Tests +You can launch the test suite with this command: + +```bash +pytest ./tests/datastore/providers/llama/test_llama_datastore.py +``` \ No newline at end of file diff --git a/docs/providers/milvus/setup.md b/docs/providers/milvus/setup.md new file mode 100644 index 000000000..eb0ca4b29 --- /dev/null +++ b/docs/providers/milvus/setup.md @@ -0,0 +1,43 @@ +# Milvus + +[Milvus](https://milvus.io/) is the open-source, cloud-native vector database that scales to billions of vectors. It's the open-source version of Zilliz. It supports: + +- Various indexing algorithms and distance metrics +- Scalar filtering and time travel searches +- Rollback and snapshots +- Multi-language SDKs +- Storage and compute separation +- Cloud scalability +- A developer-first community with multi-language support + +Visit the [Github](https://github.com/milvus-io/milvus) to learn more. + +## Deploying the Database + +You can deploy and manage Milvus using Docker Compose, Helm, K8's Operator, or Ansible. Follow the instructions [here](https://milvus.io/docs) to get started. + +**Environment Variables:** + +| Name | Required | Description | +|----------------------------| -------- |----------------------------------------------------------------------------------------------------------------------------------------------| +| `DATASTORE` | Yes | Datastore name, set to `milvus` | +| `BEARER_TOKEN` | Yes | Your bearer token | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key | +| `MILVUS_COLLECTION` | Optional | Milvus collection name, defaults to a random UUID | +| `MILVUS_HOST` | Optional | Milvus host IP, defaults to `localhost` | +| `MILVUS_PORT` | Optional | Milvus port, defaults to `19530` | +| `MILVUS_USER` | Optional | Milvus username if RBAC is enabled, defaults to `None` | +| `MILVUS_PASSWORD` | Optional | Milvus password if required, defaults to `None` | +| `MILVUS_INDEX_PARAMS` | Optional | Custom index options for the collection, defaults to `{"metric_type": "IP", "index_type": "HNSW", "params": {"M": 8, "efConstruction": 64}}` | +| `MILVUS_SEARCH_PARAMS` | Optional | Custom search options for the collection, defaults to `{"metric_type": "IP", "params": {"ef": 10}}` | +| `MILVUS_CONSISTENCY_LEVEL` | Optional | Data consistency level for the collection, defaults to `Bounded` | + +## Running Milvus Integration Tests + +A suite of integration tests is available to verify the Milvus integration. To run the tests, run the milvus docker compose found in the examples folder. + +Then, launch the test suite with this command: + +```bash +pytest ./tests/datastore/providers/milvus/test_milvus_datastore.py +``` diff --git a/docs/providers/pinecone/setup.md b/docs/providers/pinecone/setup.md new file mode 100644 index 000000000..37230d8b1 --- /dev/null +++ b/docs/providers/pinecone/setup.md @@ -0,0 +1,35 @@ +# Pinecone + +[Pinecone](https://www.pinecone.io) is a managed vector database built for speed, scale, and shipping to production sooner. To use Pinecone as your vector database provider, first get an API key by [signing up for an account](https://app.pinecone.io/). You can access your API key from the "API Keys" section in the sidebar of your dashboard. Pinecone also supports hybrid search and at the time of writing is the only datastore to support SPLADE sparse vectors natively. + +A full Jupyter notebook walkthrough for the Pinecone flavor of the retrieval plugin can be found [here](https://github.com/openai/chatgpt-retrieval-plugin/blob/main/examples/providers/pinecone/semantic-search.ipynb). There is also a [video walkthrough here](https://youtu.be/hpePPqKxNq8). + +The app will create a Pinecone index for you automatically when you run it for the first time. Just pick a name for your index and set it as an environment variable. + +**Environment Variables:** + +| Name | Required | Description | +| ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `DATASTORE` | Yes | Datastore name, set this to `pinecone` | +| `BEARER_TOKEN` | Yes | Your secret token for authenticating requests to the API | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key for generating embeddings with the `text-embedding-ada-002` model | +| `PINECONE_API_KEY` | Yes | Your Pinecone API key, found in the [Pinecone console](https://app.pinecone.io/) | +| `PINECONE_ENVIRONMENT` | Yes | Your Pinecone environment, found in the [Pinecone console](https://app.pinecone.io/), e.g. `us-west1-gcp`, `us-east-1-aws`, etc. | +| `PINECONE_INDEX` | Yes | Your chosen Pinecone index name. **Note:** Index name must consist of lower case alphanumeric characters or '-' | + +If you want to create your own index with custom configurations, you can do so using the Pinecone SDK, API, or web interface ([see docs](https://docs.pinecone.io/docs/manage-indexes)). Make sure to use a dimensionality of 1536 for the embeddings and avoid indexing on the text field in the metadata, as this will reduce the performance significantly. + +```python +# Creating index with Pinecone SDK - use only if you wish to create the index manually. + +import os, pinecone + +pinecone.init(api_key=os.environ['PINECONE_API_KEY'], + environment=os.environ['PINECONE_ENVIRONMENT']) + +pinecone.create_index(name=os.environ['PINECONE_INDEX'], + dimension=1536, + metric='cosine', + metadata_config={ + "indexed": ['source', 'source_id', 'url', 'created_at', 'author', 'document_id']}) +``` diff --git a/docs/providers/postgres/setup.md b/docs/providers/postgres/setup.md new file mode 100644 index 000000000..25c64e4cc --- /dev/null +++ b/docs/providers/postgres/setup.md @@ -0,0 +1,81 @@ +# Postgres + +Postgres Database offers an easy and efficient way to store vectors via [pgvector](https://github.com/pgvector/pgvector) extension. To use pgvector, you will need to set up a PostgreSQL database with the pgvector extension enabled or use a managed solution that provides pgvector. For a hosted/managed solution, you can use any of the cloud vendors which support [pgvector](https://github.com/pgvector/pgvector#hosted-postgres). + +- The database needs the `pgvector` extension. +- To apply required migrations you may use any tool you are more familiar with like [pgAdmin](https://www.pgadmin.org/), [DBeaver](https://dbeaver.io/), [DataGrip](https://www.jetbrains.com/datagrip/), or `psql` cli. + +**Retrieval App Environment Variables** + +| Name | Required | Description | +| ---------------- | -------- | -------------------------------------- | +| `DATASTORE` | Yes | Datastore name. Set this to `postgres` | +| `BEARER_TOKEN` | Yes | Your secret token | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key | + +**Postgres Datastore Environment Variables** + +| Name | Required | Description | Default | +| ------------- | -------- | ----------------- | ---------- | +| `PG_HOST` | Optional | Postgres host | localhost | +| `PG_PORT` | Optional | Postgres port | `5432` | +| `PG_PASSWORD` | Optional | Postgres password | `postgres` | +| `PG_USER` | Optional | Postgres username | `postgres` | +| `PG_DB` | Optional | Postgres database | `postgres` | + +## Postgres Datastore local development & testing + +In order to test your changes to the Postgres Datastore, you can run the following: + +1. You can run local or self-hosted instance of PostgreSQL with `pgvector` enabled using Docker. + +```bash +docker pull ankane/pgvector +``` + +```bash +docker run --name pgvector -e POSTGRES_PASSWORD=mysecretpassword -d postgres +``` + +Check PostgreSQL [official docker image](https://github.com/docker-library/docs/blob/master/postgres/README.md) for more options. + +2. Apply migrations using any tool you like most [pgAdmin](https://www.pgadmin.org/), [DBeaver](https://dbeaver.io/), [DataGrip](https://www.jetbrains.com/datagrip/), or `psql` cli. + +```bash +# apply migrations using psql cli +psql -h localhost -p 5432 -U postgres -d postgres -f examples/providers/supabase/migrations/20230414142107_init_pg_vector.sql +``` + +3. Export environment variables required for the Postgres Datastore + +```bash +export PG_HOST=localhost +export PG_PORT=54322 +export PG_PASSWORD=mysecretpassword +``` + +4. Run the Postgres datastore tests from the project's root directory + +```bash +# Run the Postgres datastore tests +# go to project's root directory and run +poetry run pytest -s ./tests/datastore/providers/postgres/test_postgres_datastore.py +``` + +5. When going to prod don't forget to set the password for the `postgres` user to something more secure and apply migrations. + +6. You may want to remove RLS (Row Level Security) from the `documents` table. If you are not using RLS, it is not required in this setup. But it may be useful if you want to separate documents by user or group of users, or if you want to give permissions to insert or query documents to different users. And RLS is especially important if you are willing to use PostgREST. To do so you can just remove the following statement from the `20230414142107_init_pg_vector.sql` migration file: `alter table documents enable row level security;`. + +## Indexes for Postgres + +By default, pgvector performs exact nearest neighbor search. To speed up the vector comparison, you may want to create indexes for the `embedding` column in the `documents` table. You should do this **only** after a few thousand records are inserted. + +As datasotre is using inner product for similarity search, you can add index as follows: + +```sql +create index on documents using ivfflat (embedding vector_ip_ops) with (lists = 100); +``` + +To choose `lists` constant - a good place to start is records / 1000 for up to 1M records and sqrt(records) for over 1M records + +For more information about indexes, see [pgvector docs](https://github.com/pgvector/pgvector#indexing). diff --git a/docs/providers/qdrant/setup.md b/docs/providers/qdrant/setup.md new file mode 100644 index 000000000..3fb0ef65e --- /dev/null +++ b/docs/providers/qdrant/setup.md @@ -0,0 +1,58 @@ +# Qdrant + +[Qdrant](https://qdrant.tech/) is a vector database that can store documents and vector embeddings. It can run as a self-hosted version or a managed [Qdrant Cloud](https://cloud.qdrant.io/) +solution. The configuration is almost identical for both options, except for the API key that [Qdrant Cloud](https://cloud.qdrant.io/) provides. + +**Environment Variables:** + +| Name | Required | Description | Default | +| ------------------- | -------- | ----------------------------------------------------------- | ------------------ | +| `DATASTORE` | Yes | Datastore name, set to `qdrant` | | +| `BEARER_TOKEN` | Yes | Secret token | | +| `OPENAI_API_KEY` | Yes | OpenAI API key | | +| `QDRANT_URL` | Yes | Qdrant instance URL | `http://localhost` | +| `QDRANT_PORT` | Optional | TCP port for Qdrant HTTP communication | `6333` | +| `QDRANT_GRPC_PORT` | Optional | TCP port for Qdrant GRPC communication | `6334` | +| `QDRANT_API_KEY` | Optional | Qdrant API key for [Qdrant Cloud](https://cloud.qdrant.io/) | | +| `QDRANT_COLLECTION` | Optional | Qdrant collection name | `document_chunks` | + +## Qdrant Cloud + +For a hosted [Qdrant Cloud](https://cloud.qdrant.io/) version, provide the Qdrant instance +URL and the API key from the [Qdrant Cloud UI](https://cloud.qdrant.io/). + +**Example:** + +```bash +QDRANT_URL="https://YOUR-CLUSTER-URL.aws.cloud.qdrant.io" +QDRANT_API_KEY="" +``` + +The other parameters are optional and can be changed if needed. + +## Self-hosted Qdrant Instance + +For a self-hosted version, use Docker containers or the official Helm chart for deployment. The only +required parameter is the `QDRANT_URL` that points to the Qdrant server URL. + +**Example:** + +```bash +QDRANT_URL="http://YOUR_HOST.example.com:6333" +``` + +The other parameters are optional and can be changed if needed. + +## Running Qdrant Integration Tests + +A suite of integration tests verifies the Qdrant integration. To run it, start a local Qdrant instance in a Docker container. + +```bash +docker run -p "6333:6333" -p "6334:6334" qdrant/qdrant:v1.0.3 +``` + +Then, launch the test suite with this command: + +```bash +pytest ./tests/datastore/providers/qdrant/test_qdrant_datastore.py +``` diff --git a/docs/providers/redis/setup.md b/docs/providers/redis/setup.md new file mode 100644 index 000000000..37f993941 --- /dev/null +++ b/docs/providers/redis/setup.md @@ -0,0 +1,37 @@ +# Redis + +[Redis](https://redis.com/solutions/use-cases/vector-database/) is a real-time data platform that supports a variety of use cases for everyday applications as well as AI/ML workloads. Use Redis as a low-latency vector engine by creating a Redis database with the [Redis Stack docker container](/examples/docker/redis/docker-compose.yml). For a hosted/managed solution, try [Redis Cloud](https://app.redislabs.com/#/). See more helpful examples of Redis as a vector database [here](https://github.com/RedisVentures/redis-ai-resources). + +- The database **needs the RediSearch module (>=v2.6) and RedisJSON**, which are included in the self-hosted docker compose above. +- Run the App with the Redis docker image: `docker compose up -d` in [this dir](/examples/docker/redis/). +- The app automatically creates a Redis vector search index on the first run. Optionally, create a custom index with a specific name and set it as an environment variable (see below). +- To enable more hybrid searching capabilities, adjust the document schema [here](/datastore/providers/redis_datastore.py). + +**Environment Variables:** + +| Name | Required | Description | Default | +| ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- | ----------- | +| `DATASTORE` | Yes | Datastore name, set to `redis` | | +| `BEARER_TOKEN` | Yes | Secret token | | +| `OPENAI_API_KEY` | Yes | OpenAI API key | | +| `REDIS_HOST` | Optional | Redis host url | `localhost` | +| `REDIS_PORT` | Optional | Redis port | `6379` | +| `REDIS_PASSWORD` | Optional | Redis password | none | +| `REDIS_INDEX_NAME` | Optional | Redis vector index name | `index` | +| `REDIS_DOC_PREFIX` | Optional | Redis key prefix for the index | `doc` | +| `REDIS_DISTANCE_METRIC` | Optional | Vector similarity distance metric | `COSINE` | +| `REDIS_INDEX_TYPE` | Optional | [Vector index algorithm type](https://redis.io/docs/stack/search/reference/vectors/#creation-attributes-per-algorithm) | `FLAT` | + + +## Redis Datastore development & testing +In order to test your changes to the Redis Datastore, you can run the following commands: + +```bash +# Run the Redis stack docker image +docker run -it --rm -p 6379:6379 redis/redis-stack-server:latest +``` + +```bash +# Run the Redis datastore tests +poetry run pytest -s ./tests/datastore/providers/redis/test_redis_datastore.py +``` \ No newline at end of file diff --git a/docs/providers/supabase/setup.md b/docs/providers/supabase/setup.md new file mode 100644 index 000000000..8d2f05a73 --- /dev/null +++ b/docs/providers/supabase/setup.md @@ -0,0 +1,87 @@ +# Supabase + +[Supabase](https://supabase.com/blog/openai-embeddings-postgres-vector) offers an easy and efficient way to store vectors via [pgvector](https://github.com/pgvector/pgvector) extension for Postgres Database. [You can use Supabase CLI](https://github.com/supabase/cli) to set up a whole Supabase stack locally or in the cloud or you can also use docker-compose, k8s and other options available. For a hosted/managed solution, try [Supabase.com](https://supabase.com/) and unlock the full power of Postgres with built-in authentication, storage, auto APIs, and Realtime features. See more helpful examples of Supabase & pgvector as a vector database [here](https://github.com/supabase-community/nextjs-openai-doc-search). + +- The database needs the `pgvector` extension, which is included in [Supabase distribution of Postgres](https://github.com/supabase/postgres). +- It is possible to provide a Postgres connection string and an app will add `documents` table, query Postgres function, and `pgvector` extension automatically. +- But it is recommended to separate the migration process from an app. And execute the migration script in a different pipeline by using SQL statements from `_init_db()` function in [Supabase datastore provider](/datastore/providers/supabase_datastore.py). + +**Retrieval App Environment Variables** + +| Name | Required | Description | +| ---------------- | -------- | -------------------------------------- | +| `DATASTORE` | Yes | Datastore name. Set this to `supabase` | +| `BEARER_TOKEN` | Yes | Your secret token | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key | + +**Supabase Datastore Environment Variables** + +| Name | Required | Description | Default | +| --------------------------- | -------- | ------------------------------------------------------------------------------ | ------- | +| `SUPABASE_URL` | Yes | Supabase Project URL | | +| `SUPABASE_ANON_KEY` | Optional | Supabase Project API anon key | | +| `SUPABASE_SERVICE_ROLE_KEY` | Optional | Supabase Project API service key, will be used if provided instead of anon key | | + +## Supabase Datastore local development & testing + +In order to test your changes to the Supabase Datastore, you can run the following commands: + +1. Install [Supabase CLI](https://github.com/supabase/cli) and [Docker](https://docs.docker.com/get-docker/) + +2. Run the Supabase `start` command from `examples/providers` directory. Config for Supabase local setup is available in `examples/providers/supabase` directory with required migrations. + +```bash +# Run the Supabase stack using cli in docker +# go to examples/providers and run supabase start +cd examples/providers +supabase start +``` + +3. Supabase `start` will download docker images and launch Supabase stack locally. You will see similar output: + +```bash +Applying migration 20230414142107_init_pg_vector.sql... +Seeding data supabase/seed.sql... +Started supabase local development setup. + + API URL: http://localhost:54321 + DB URL: postgresql://postgres:postgres@localhost:54322/postgres + Studio URL: http://localhost:54323 + Inbucket URL: http://localhost:54324 + JWT secret: super-secret-jwt-token-with-at-least-32-characters-long + anon key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0 +service_role key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU +``` + +4. Export environment variables required for the Supabase Datastore + +```bash +export SUPABASE_URL=http://localhost:54321 +export SUPABASE_SERVICE_ROLE_KEY='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU' +``` + +5. Run the Supabase datastore tests from the project's root directory + +```bash +# Run the Supabase datastore tests +# go to project's root directory and run +poetry run pytest -s ./tests/datastore/providers/supabase/test_supabase_datastore.py +``` + +6. When you go to prod (if cloud hosted) it is recommended to link your supabase project with the local setup from `examples/providers/supabase`. All migrations will be synced with the cloud project after you run `supabase db push`. Or you can manually apply migrations from `examples/providers/supabase/migrations` directory. + +7. You might want to add RLS policies to the `documents` table. Or you can just continue using it on the server side only with the service role key. But you should not use service role key on the client side in any case. + +## Indexes for Postgres + +By default, pgvector performs exact nearest neighbor search. To speed up the vector comparison, you may want to create indexes for the `embedding` column in the `documents` table. You should do this **only** after a few thousand records are inserted. + +As datasotre is using inner product for similarity search, you can add index as follows: + +```sql +create index on documents using ivfflat (embedding vector_ip_ops) with (lists = 100); +``` + +To choose `lists` constant - a good place to start is records / 1000 for up to 1M records and sqrt(records) for over 1M records + +For more information about indexes, see [pgvector docs](https://github.com/pgvector/pgvector#indexing). diff --git a/docs/providers/weaviate/setup.md b/docs/providers/weaviate/setup.md new file mode 100644 index 000000000..31916329e --- /dev/null +++ b/docs/providers/weaviate/setup.md @@ -0,0 +1,79 @@ +# Weaviate + +## Set up a Weaviate Instance + +[Weaviate](https://weaviate.io/) is an open-source vector search engine designed to scale seamlessly into billions of data objects. This implementation supports hybrid search out-of-the-box (meaning it will perform better for keyword searches). + +You can run Weaviate in 4 ways: + +- **SaaS** – with [Weaviate Cloud Services (WCS)](https://weaviate.io/pricing). + + WCS is a fully managed service that takes care of hosting, scaling, and updating your Weaviate instance. You can try it out for free with a sandbox that lasts for 30 days. + + To set up a SaaS Weaviate instance with WCS: + + 1. Navigate to [Weaviate Cloud Console](https://console.weaviate.io/). + 2. Register or sign in to your WCS account. + 3. Create a new cluster with the following settings: + - `Name` – a unique name for your cluster. The name will become part of the URL used to access this instance. + - `Subscription Tier` – Sandbox for a free trial, or contact [hello@weaviate.io](mailto:hello@weaviate.io) for other options. + - `Weaviate Version` - The latest version by default. + - `OIDC Authentication` – Enabled by default. This requires a username and password to access your instance. + 4. Wait for a few minutes until your cluster is ready. You will see a green tick ✔️ when it's done. Copy your cluster URL. + +- **Hybrid SaaS** + + > If you need to keep your data on-premise for security or compliance reasons, Weaviate also offers a Hybrid SaaS option: Weaviate runs within your cloud instances, but the cluster is managed remotely by Weaviate. This gives you the benefits of a managed service without sending data to an external party. + + The Weaviate Hybrid SaaS is a custom solution. If you are interested in this option, please reach out to [hello@weaviate.io](mailto:hello@weaviate.io). + +- **Self-hosted** – with a Docker container + + To set up a Weaviate instance with Docker: + + 1. [Install Docker](https://docs.docker.com/engine/install/) on your local machine if it is not already installed. + 2. [Install the Docker Compose Plugin](https://docs.docker.com/compose/install/) + 3. Download a `docker-compose.yml` file with this `curl` command: + + ``` + curl -o docker-compose.yml "https://configuration.weaviate.io/v2/docker-compose/docker-compose.yml?modules=standalone&runtime=docker-compose&weaviate_version=v1.18.0" + ``` + + Alternatively, you can use Weaviate's docker compose [configuration tool](https://weaviate.io/developers/weaviate/installation/docker-compose) to generate your own `docker-compose.yml` file. + + 4. Run `docker compose up -d` to spin up a Weaviate instance. + + > To shut it down, run `docker compose down`. + +- **Self-hosted** – with a Kubernetes cluster + + To configure a self-hosted instance with Kubernetes, follow Weaviate's [documentation](https://weaviate.io/developers/weaviate/installation/kubernetes). + +## Configure Weaviate Environment Variables + +You need to set some environment variables to connect to your Weaviate instance. + +**Retrieval App Environment Variables** + +| Name | Required | Description | +| ---------------- | -------- |--------------------------------------------------------------------------------------| +| `DATASTORE` | Yes | Datastore name. Set this to `weaviate` | +| `BEARER_TOKEN` | Yes | Your [secret token](/README.md#general-environment-variables) (not the Weaviate one) | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key | + +**Weaviate Datastore Environment Variables** + +| Name | Required | Description | Default | +|------------------| -------- | ------------------------------------------------------------------ | ------------------ | +| `WEAVIATE_URL` | Optional | Your weaviate instance's url/WCS endpoint | `http://localhost:8080` | | +| `WEAVIATE_CLASS` | Optional | Your chosen Weaviate class/collection name to store your documents | OpenAIDocument | + +**Weaviate Auth Environment Variables** + +If using WCS instances, set the following environment variables: + +| Name | Required | Description | +| ------------------- | -------- | ------------------------------ | +| `WEAVIATE_API_KEY` | Yes | Your API key WCS | + +Learn more about accessing your [WCS API key](https://weaviate.io/developers/wcs/guides/authentication#access-api-keys). \ No newline at end of file diff --git a/docs/providers/zilliz/setup.md b/docs/providers/zilliz/setup.md new file mode 100644 index 000000000..fddde3aa9 --- /dev/null +++ b/docs/providers/zilliz/setup.md @@ -0,0 +1,46 @@ +# Zilliz + +[Zilliz](https://zilliz.com) is a managed cloud-native vector database designed for the billion scale. Zilliz offers many key features, such as: + +- Multiple indexing algorithms +- Multiple distance metrics +- Scalar filtering +- Time travel searches +- Rollback and with snapshots +- Full RBAC +- 99.9% uptime +- Separated storage and compute +- Multi-language SDK's + +Find more information [here](https://zilliz.com). + +**Self Hosted vs SaaS** + +Zilliz is a SaaS database, but offers an open-source solution, Milvus. Both options offer fast searches at the billion scale, but Zilliz handles data management for you. It automatically scales compute and storage resources and creates optimal indexes for your data. See the comparison [here](https://zilliz.com/doc/about_zilliz_cloud). + +## Deploying the Database + +Zilliz Cloud is deployable in a few simple steps. First, create an account [here](https://cloud.zilliz.com/signup). Once you have an account set up, follow the guide [here](https://zilliz.com/doc/quick_start) to set up a database and get the parameters needed for this application. + +Environment Variables: + +| Name | Required | Description | +|----------------------------| -------- |------------------------------------------------------------------| +| `DATASTORE` | Yes | Datastore name, set to `zilliz` | +| `BEARER_TOKEN` | Yes | Your secret token | +| `OPENAI_API_KEY` | Yes | Your OpenAI API key | +| `ZILLIZ_COLLECTION` | Optional | Zilliz collection name. Defaults to a random UUID | +| `ZILLIZ_URI` | Yes | URI for the Zilliz instance | +| `ZILLIZ_USER` | Yes | Zilliz username | +| `ZILLIZ_PASSWORD` | Yes | Zilliz password | +| `ZILLIZ_CONSISTENCY_LEVEL` | Optional | Data consistency level for the collection, defaults to `Bounded` | + +## Running Zilliz Integration Tests + +A suite of integration tests is available to verify the Zilliz integration. To run the tests, create a Zilliz database and update the environment variables. + +Then, launch the test suite with this command: + +```bash +pytest ./tests/datastore/providers/zilliz/test_zilliz_datastore.py +``` diff --git a/examples/authentication-methods/no-auth/ai-plugin.json b/examples/authentication-methods/no-auth/ai-plugin.json new file mode 100644 index 000000000..024891926 --- /dev/null +++ b/examples/authentication-methods/no-auth/ai-plugin.json @@ -0,0 +1,18 @@ +{ + "schema_version": "v1", + "name_for_model": "retrieval", + "name_for_human": "Retrieval Plugin", + "description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.", + "description_for_human": "Search through your documents.", + "auth": { + "type": "none" + }, + "api": { + "type": "openapi", + "url": "https://your-app-url.com/.well-known/openapi.yaml" + }, + "logo_url": "https://your-app-url.com/.well-known/logo.png", + "contact_email": "hello@contact.com", + "legal_info_url": "hello@legal.com" +} + diff --git a/examples/authentication-methods/no-auth/main.py b/examples/authentication-methods/no-auth/main.py new file mode 100644 index 000000000..961c725c1 --- /dev/null +++ b/examples/authentication-methods/no-auth/main.py @@ -0,0 +1,144 @@ +# This is a version of the main.py file found in ../../../server/main.py without authentication. +# Copy and paste this into the main file at ../../../server/main.py if you choose to use no authentication for your retrieval plugin. +from typing import Optional +import uvicorn +from fastapi import FastAPI, File, Form, HTTPException, Body, UploadFile +from fastapi.staticfiles import StaticFiles +from loguru import logger + +from models.api import ( + DeleteRequest, + DeleteResponse, + QueryRequest, + QueryResponse, + UpsertRequest, + UpsertResponse, +) +from datastore.factory import get_datastore +from services.file import get_document_from_file + +from models.models import DocumentMetadata, Source + + +app = FastAPI() +app.mount("/.well-known", StaticFiles(directory=".well-known"), name="static") + +# Create a sub-application, in order to access just the query endpoints in the OpenAPI schema, found at http://0.0.0.0:8000/sub/openapi.json when the app is running locally +sub_app = FastAPI( + title="Retrieval Plugin API", + description="A retrieval API for querying and filtering documents based on natural language queries and metadata", + version="1.0.0", + servers=[{"url": "https://your-app-url.com"}], +) +app.mount("/sub", sub_app) + + +@app.post( + "/upsert-file", + response_model=UpsertResponse, +) +async def upsert_file( + file: UploadFile = File(...), + metadata: Optional[str] = Form(None), +): + try: + metadata_obj = ( + DocumentMetadata.parse_raw(metadata) + if metadata + else DocumentMetadata(source=Source.file) + ) + except: + metadata_obj = DocumentMetadata(source=Source.file) + + document = await get_document_from_file(file, metadata_obj) + + try: + ids = await datastore.upsert([document]) + return UpsertResponse(ids=ids) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail=f"str({e})") + + +@app.post( + "/upsert", + response_model=UpsertResponse, +) +async def upsert( + request: UpsertRequest = Body(...), +): + try: + ids = await datastore.upsert(request.documents) + return UpsertResponse(ids=ids) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@app.post( + "/query", + response_model=QueryResponse, +) +async def query_main( + request: QueryRequest = Body(...), +): + try: + results = await datastore.query( + request.queries, + ) + return QueryResponse(results=results) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@sub_app.post( + "/query", + response_model=QueryResponse, + description="Accepts search query objects with query and optional filter. Break down complex questions into sub-questions. Refine results by criteria, e.g. time / source, don't do this often. Split queries if ResponseTooLargeError occurs.", +) +async def query( + request: QueryRequest = Body(...), +): + try: + results = await datastore.query( + request.queries, + ) + return QueryResponse(results=results) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@app.delete( + "/delete", + response_model=DeleteResponse, +) +async def delete( + request: DeleteRequest = Body(...), +): + if not (request.ids or request.filter or request.delete_all): + raise HTTPException( + status_code=400, + detail="One of ids, filter, or delete_all is required", + ) + try: + success = await datastore.delete( + ids=request.ids, + filter=request.filter, + delete_all=request.delete_all, + ) + return DeleteResponse(success=success) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@app.on_event("startup") +async def startup(): + global datastore + datastore = await get_datastore() + + +def start(): + uvicorn.run("server.main:app", host="0.0.0.0", port=8000, reload=True) diff --git a/examples/authentication-methods/oauth/ai-plugin.json b/examples/authentication-methods/oauth/ai-plugin.json new file mode 100644 index 000000000..e98e7aa2f --- /dev/null +++ b/examples/authentication-methods/oauth/ai-plugin.json @@ -0,0 +1,25 @@ +{ + "schema_version": "v1", + "name_for_model": "retrieval", + "name_for_human": "Retrieval Plugin", + "description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.", + "description_for_human": "Search through your documents.", + "auth" : { + "type":"oauth", + "client_url":"e.g. https:///oauth/v2/authorize", + "authorization_url":"e.g. https:///api/oauth.v2.access", + "scope":"search:read", + "authorization_content_type":"application/x-www-form-urlencoded", + "verification_tokens":{ + "openai":"" + } + }, + "api":{ + "url": "https://your-app-url.com/.well-known/openapi.yaml", + "has_user_authentication":true, + "type":"openapi" + }, + "logo_url": "https://your-app-url.com/.well-known/logo.png", + "contact_email": "hello@contact.com", + "legal_info_url": "hello@legal.com" +} diff --git a/examples/authentication-methods/service-http/ai-plugin.json b/examples/authentication-methods/service-http/ai-plugin.json new file mode 100644 index 000000000..4bf89ba48 --- /dev/null +++ b/examples/authentication-methods/service-http/ai-plugin.json @@ -0,0 +1,22 @@ +{ + "schema_version": "v1", + "name_for_model": "retrieval", + "name_for_human": "Retrieval Plugin", + "description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.", + "description_for_human": "Search through your documents.", + "auth":{ + "type":"service_http", + "authorization_type":"bearer", + "verification_tokens":{ + "openai":"" + } + }, + "api":{ + "url": "https://your-app-url.com/.well-known/openapi.yaml", + "has_user_authentication":false, + "type":"openapi" + }, + "logo_url": "https://your-app-url.com/.well-known/logo.png", + "contact_email": "hello@contact.com", + "legal_info_url": "hello@legal.com" +} diff --git a/examples/authentication-methods/user-http/ai-plugin.json b/examples/authentication-methods/user-http/ai-plugin.json new file mode 100644 index 000000000..1c4e50187 --- /dev/null +++ b/examples/authentication-methods/user-http/ai-plugin.json @@ -0,0 +1,19 @@ +{ + "schema_version": "v1", + "name_for_model": "retrieval", + "name_for_human": "Retrieval Plugin", + "description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.", + "description_for_human": "Search through your documents.", + "auth": { + "type": "user_http", + "authorization_type": "bearer" + }, + "api": { + "type": "openapi", + "url": "https://your-app-url.com/.well-known/openapi.yaml", + "has_user_authentication": false + }, + "logo_url": "https://your-app-url.com/.well-known/logo.png", + "contact_email": "hello@contact.com", + "legal_info_url": "hello@legal.com" +} \ No newline at end of file diff --git a/examples/docker/elasticsearch/README.md b/examples/docker/elasticsearch/README.md new file mode 100644 index 000000000..c3ed3533c --- /dev/null +++ b/examples/docker/elasticsearch/README.md @@ -0,0 +1,7 @@ +## Running Elasticsearch + +```bash +docker-compose up -d +``` + +should now be running at http://localhost:9200 diff --git a/examples/docker/elasticsearch/docker-compose.yaml b/examples/docker/elasticsearch/docker-compose.yaml new file mode 100644 index 000000000..23d83c85b --- /dev/null +++ b/examples/docker/elasticsearch/docker-compose.yaml @@ -0,0 +1,27 @@ +version: "3.7" + +services: + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:8.8.2 + container_name: elasticsearch + environment: + - discovery.type=single-node + - node.name=elasticsearch + - xpack.security.enabled=false + ulimits: + memlock: + soft: -1 + hard: -1 + ports: + - "9200:9200" + networks: + - esnet + volumes: + - esdata:/usr/share/elasticsearch/data + +networks: + esnet: + +volumes: + esdata: + driver: local diff --git a/examples/docker/milvus/docker-compose.yaml b/examples/docker/milvus/docker-compose.yaml new file mode 100644 index 000000000..655069cef --- /dev/null +++ b/examples/docker/milvus/docker-compose.yaml @@ -0,0 +1,49 @@ +version: '3.5' + +services: + etcd: + container_name: milvus-etcd + image: quay.io/coreos/etcd:v3.5.0 + environment: + - ETCD_AUTO_COMPACTION_MODE=revision + - ETCD_AUTO_COMPACTION_RETENTION=1000 + - ETCD_QUOTA_BACKEND_BYTES=4294967296 + - ETCD_SNAPSHOT_COUNT=50000 + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd + command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd + + minio: + container_name: milvus-minio + image: minio/minio:RELEASE.2023-03-20T20-16-18Z + environment: + MINIO_ACCESS_KEY: minioadmin + MINIO_SECRET_KEY: minioadmin + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data + command: minio server /minio_data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + + standalone: + container_name: milvus-standalone + image: milvusdb/milvus:v2.2.5 + command: ["milvus", "run", "standalone"] + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus + ports: + - "19530:19530" + - "9091:9091" + depends_on: + - "etcd" + - "minio" + +networks: + default: + name: milvus \ No newline at end of file diff --git a/examples/docker/qdrant/README.md b/examples/docker/qdrant/README.md new file mode 100644 index 000000000..6d00b25ae --- /dev/null +++ b/examples/docker/qdrant/README.md @@ -0,0 +1,46 @@ +# Running the Retrieval Plugin with Qdrant in Docker Containers + +To set up the ChatGPT retrieval plugin with a single instance of a Qdrant vector database, follow these steps: + +## Set Environment Variables + +Set the following environment variables: + +```bash +# Provide your own OpenAI API key in order to start. +export OPENAI_API_KEY="" +# This is an example of a minimal token generated by https://jwt.io/ +export BEARER_TOKEN="" +``` + +## Run Qdrant and the Retrieval Plugin in Docker Containers + +Both Docker containers might be launched with docker-compose: + +```bash +docker-compose up -d +``` + +## Store the Documents + +Store an initial batch of documents by calling the `/upsert` endpoint: + +```bash +curl -X POST \ + -H "Content-type: application/json" \ + -H "Authorization: Bearer $BEARER_TOKEN" \ + --data-binary '@documents.json' \ + "http://localhost:80/upsert" +``` + +## Send a Test Query + +You can query Qdrant to find relevant document chunks by calling the `/query` endpoint: + +```bash +curl -X POST \ + -H "Content-type: application/json" \ + -H "Authorization: Bearer $BEARER_TOKEN" \ + --data-binary '@queries.json' \ + "http://localhost:80/query" +``` diff --git a/examples/docker/qdrant/docker-compose.yaml b/examples/docker/qdrant/docker-compose.yaml new file mode 100644 index 000000000..ead9fd6e3 --- /dev/null +++ b/examples/docker/qdrant/docker-compose.yaml @@ -0,0 +1,17 @@ +services: + retrieval-app: + build: + context: ../../../ + dockerfile: Dockerfile + image: openai/chatgpt-retrieval-plugin + ports: + - "80:80" + depends_on: + - qdrant + environment: + DATASTORE: "qdrant" + QDRANT_URL: "http://qdrant" + BEARER_TOKEN: "${BEARER_TOKEN}" + OPENAI_API_KEY: "${OPENAI_API_KEY}" + qdrant: + image: qdrant/qdrant:v1.0.3 \ No newline at end of file diff --git a/examples/docker/qdrant/documents.json b/examples/docker/qdrant/documents.json new file mode 100644 index 000000000..7dc6572fb --- /dev/null +++ b/examples/docker/qdrant/documents.json @@ -0,0 +1,23 @@ +{ + "documents": [ + { + "id": "openai", + "text": "OpenAI is an AI research and deployment company. Our mission is to ensure that artificial general intelligence benefits all of humanity.", + "metadata": { + "created_at": "2023-03-14" + } + }, + { + "id": "chatgpt", + "text": "ChatGPT is a sibling model to InstructGPT, which is trained to follow an instruction in a prompt and provide a detailed response. The dialogue format makes it possible for ChatGPT to answer followup questions, admit its mistakes, challenge incorrect premises, and reject inappropriate requests." + }, + { + "id": "qdrant", + "text": "Qdrant is a vector similarity engine & vector database. It deploys as an API service providing search for the nearest high-dimensional vectors. With Qdrant, embeddings or neural network encoders can be turned into full-fledged applications for matching, searching, recommending, and much more!", + "metadata": { + "created_at": "2023-03-14", + "author": "Kacper Łukawski" + } + } + ] +} \ No newline at end of file diff --git a/examples/docker/qdrant/queries.json b/examples/docker/qdrant/queries.json new file mode 100644 index 000000000..6d967e20d --- /dev/null +++ b/examples/docker/qdrant/queries.json @@ -0,0 +1,7 @@ +{ + "queries": [ + { + "query": "What vector database should I use?" + } + ] +} \ No newline at end of file diff --git a/examples/docker/redis/docker-compose.yml b/examples/docker/redis/docker-compose.yml new file mode 100644 index 000000000..b3c197e08 --- /dev/null +++ b/examples/docker/redis/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3.9" + +services: + redis: + image: redis/redis-stack-server:latest + ports: + - "6379:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "-h", "localhost", "-p", "6379", "ping"] + interval: 2s + timeout: 1m30s + retries: 5 + start_period: 5s + +volumes: + redis_data: \ No newline at end of file diff --git a/examples/memory/README.md b/examples/memory/README.md new file mode 100644 index 000000000..ccf2e03cf --- /dev/null +++ b/examples/memory/README.md @@ -0,0 +1,15 @@ +# ChatGPT Retrieval Plugin with Memory + +This example demonstrates how to give ChatGPT the ability to remember information from conversations and store it in the retrieval plugin for later use. By allowing the model to access the `/upsert` endpoint, it can save snippets from the conversation to the vector database and retrieve them when needed. + +## Setup + +To enable ChatGPT to save information from conversations, follow these steps: + +- Copy the contents of [openapi.yaml](openapi.yaml) into the main [openapi.yaml](../../.well-known/openapi.yaml) file. + +- Copy the contents of [ai-plugin.json](ai-plugin.json) into the main [ai-plugin.json](../../.well-known/ai-plugin.json) file. + +**Optional:** If you make any changes to the plugin instructions or metadata models, you can also copy the contents of [main.py](main.py) into the main [main.py](../../server/main.py) file. This will allow you to access the openapi.json at `http://0.0.0.0:8000/sub/openapi.json` when you run the app locally. You can convert from JSON to YAML format with [Swagger Editor](https://editor.swagger.io/). Alternatively, you can replace the openapi.yaml file with an openapi.json file. + +After completing these steps, ChatGPT will be able to access your plugin's `/upsert` endpoint and save snippets from the conversation to the vector database. This enables the model to remember information from previous conversations and retrieve it when needed. diff --git a/examples/memory/ai-plugin.json b/examples/memory/ai-plugin.json new file mode 100644 index 000000000..953fff590 --- /dev/null +++ b/examples/memory/ai-plugin.json @@ -0,0 +1,19 @@ +{ + "schema_version": "v1", + "name_for_model": "retrieval", + "name_for_human": "Retrieval Plugin", + "description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information, or asks you to save information for later.", + "description_for_human": "Search through your documents.", + "auth": { + "type": "user_http", + "authorization_type": "bearer" + }, + "api": { + "type": "openapi", + "url": "https://your-app-url.com/.well-known/openapi.yaml", + "has_user_authentication": false + }, + "logo_url": "https://your-app-url.com/.well-known/logo.png", + "contact_email": "hello@contact.com", + "legal_info_url": "hello@legal.com" + } \ No newline at end of file diff --git a/examples/memory/main.py b/examples/memory/main.py new file mode 100644 index 000000000..c94d3f94d --- /dev/null +++ b/examples/memory/main.py @@ -0,0 +1,183 @@ +# This is a version of the main.py file found in ../../server/main.py that also gives ChatGPT access to the upsert endpoint +# (allowing it to save information from the chat back to the vector) database. +# Copy and paste this into the main file at ../../server/main.py if you choose to give the model access to the upsert endpoint +# and want to access the openapi.json when you run the app locally at http://0.0.0.0:8000/sub/openapi.json. +import os +from typing import Optional +import uvicorn +from fastapi import FastAPI, File, Form, HTTPException, Depends, Body, UploadFile +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials +from fastapi.staticfiles import StaticFiles +from loguru import logger + +from models.api import ( + DeleteRequest, + DeleteResponse, + QueryRequest, + QueryResponse, + UpsertRequest, + UpsertResponse, +) +from datastore.factory import get_datastore +from services.file import get_document_from_file + +from models.models import DocumentMetadata, Source + + +bearer_scheme = HTTPBearer() +BEARER_TOKEN = os.environ.get("BEARER_TOKEN") +assert BEARER_TOKEN is not None + + +def validate_token(credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme)): + if credentials.scheme != "Bearer" or credentials.credentials != BEARER_TOKEN: + raise HTTPException(status_code=401, detail="Invalid or missing token") + return credentials + + +app = FastAPI() +app.mount("/.well-known", StaticFiles(directory=".well-known"), name="static") + +# Create a sub-application, in order to access just the upsert and query endpoints in the OpenAPI schema, found at http://0.0.0.0:8000/sub/openapi.json when the app is running locally +sub_app = FastAPI( + title="Retrieval Plugin API", + description="A retrieval API for querying and filtering documents based on natural language queries and metadata", + version="1.0.0", + servers=[{"url": "https://your-app-url.com"}], + dependencies=[Depends(validate_token)], +) +app.mount("/sub", sub_app) + + +@app.post( + "/upsert-file", + response_model=UpsertResponse, +) +async def upsert_file( + file: UploadFile = File(...), + metadata: Optional[str] = Form(None), +): + try: + metadata_obj = ( + DocumentMetadata.parse_raw(metadata) + if metadata + else DocumentMetadata(source=Source.file) + ) + except: + metadata_obj = DocumentMetadata(source=Source.file) + + document = await get_document_from_file(file, metadata_obj) + + try: + ids = await datastore.upsert([document]) + return UpsertResponse(ids=ids) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail=f"str({e})") + + +@app.post( + "/upsert", + response_model=UpsertResponse, +) +async def upsert_main( + request: UpsertRequest = Body(...), + token: HTTPAuthorizationCredentials = Depends(validate_token), +): + try: + ids = await datastore.upsert(request.documents) + return UpsertResponse(ids=ids) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@sub_app.post( + "/upsert", + response_model=UpsertResponse, + # NOTE: We are describing the shape of the API endpoint input due to a current limitation in parsing arrays of objects from OpenAPI schemas. This will not be necessary in the future. + description="Save chat information. Accepts an array of documents with text (potential questions + conversation text), metadata (source 'chat' and timestamp, no ID as this will be generated). Confirm with the user before saving, ask for more details/context.", +) +async def upsert( + request: UpsertRequest = Body(...), + token: HTTPAuthorizationCredentials = Depends(validate_token), +): + try: + ids = await datastore.upsert(request.documents) + return UpsertResponse(ids=ids) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@app.post( + "/query", + response_model=QueryResponse, +) +async def query_main( + request: QueryRequest = Body(...), + token: HTTPAuthorizationCredentials = Depends(validate_token), +): + try: + results = await datastore.query( + request.queries, + ) + return QueryResponse(results=results) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@sub_app.post( + "/query", + response_model=QueryResponse, + # NOTE: We are describing the shape of the API endpoint input due to a current limitation in parsing arrays of objects from OpenAPI schemas. This will not be necessary in the future. + description="Accepts search query objects array each with query and optional filter. Break down complex questions into sub-questions. Refine results by criteria, e.g. time / source, don't do this often. Split queries if ResponseTooLargeError occurs.", +) +async def query( + request: QueryRequest = Body(...), + token: HTTPAuthorizationCredentials = Depends(validate_token), +): + try: + results = await datastore.query( + request.queries, + ) + return QueryResponse(results=results) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@app.delete( + "/delete", + response_model=DeleteResponse, +) +async def delete( + request: DeleteRequest = Body(...), + token: HTTPAuthorizationCredentials = Depends(validate_token), +): + if not (request.ids or request.filter or request.delete_all): + raise HTTPException( + status_code=400, + detail="One of ids, filter, or delete_all is required", + ) + try: + success = await datastore.delete( + ids=request.ids, + filter=request.filter, + delete_all=request.delete_all, + ) + return DeleteResponse(success=success) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=500, detail="Internal Service Error") + + +@app.on_event("startup") +async def startup(): + global datastore + datastore = await get_datastore() + + +def start(): + uvicorn.run("server.main:app", host="0.0.0.0", port=8000, reload=True) diff --git a/examples/memory/openapi.yaml b/examples/memory/openapi.yaml new file mode 100644 index 000000000..43b3db9aa --- /dev/null +++ b/examples/memory/openapi.yaml @@ -0,0 +1,276 @@ +openapi: 3.0.2 +info: + title: Retrieval Plugin API + description: A retrieval API for querying and filtering documents based on natural language queries and metadata + version: 1.0.0 +servers: + - url: https://your-app-url.com +paths: + /upsert: + post: + summary: Upsert + description: Save chat information. Accepts an array of documents with text (potential questions + conversation text), metadata (source 'chat' and timestamp, no ID as this will be generated). Confirm with the user before saving, ask for more details/context. + operationId: upsert_upsert_post + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpsertRequest" + required: true + responses: + "200": + description: Successful Response + content: + application/json: + schema: + $ref: "#/components/schemas/UpsertResponse" + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + security: + - HTTPBearer: [] + /query: + post: + summary: Query + description: Accepts search query objects array each with query and optional filter. Break down complex questions into sub-questions. Refine results by criteria, e.g. time / source, don't do this often. Split queries if ResponseTooLargeError occurs. + operationId: query_query_post + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/QueryRequest" + required: true + responses: + "200": + description: Successful Response + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + security: + - HTTPBearer: [] +components: + schemas: + Document: + title: Document + required: + - text + type: object + properties: + id: + title: Id + type: string + text: + title: Text + type: string + metadata: + $ref: "#/components/schemas/DocumentMetadata" + DocumentChunkMetadata: + title: DocumentChunkMetadata + type: object + properties: + source: + $ref: "#/components/schemas/Source" + source_id: + title: Source Id + type: string + url: + title: Url + type: string + created_at: + title: Created At + type: string + author: + title: Author + type: string + document_id: + title: Document Id + type: string + DocumentChunkWithScore: + title: DocumentChunkWithScore + required: + - text + - metadata + - score + type: object + properties: + id: + title: Id + type: string + text: + title: Text + type: string + metadata: + $ref: "#/components/schemas/DocumentChunkMetadata" + embedding: + title: Embedding + type: array + items: + type: number + score: + title: Score + type: number + DocumentMetadata: + title: DocumentMetadata + type: object + properties: + source: + $ref: "#/components/schemas/Source" + source_id: + title: Source Id + type: string + url: + title: Url + type: string + created_at: + title: Created At + type: string + author: + title: Author + type: string + DocumentMetadataFilter: + title: DocumentMetadataFilter + type: object + properties: + document_id: + title: Document Id + type: string + source: + $ref: "#/components/schemas/Source" + source_id: + title: Source Id + type: string + author: + title: Author + type: string + start_date: + title: Start Date + type: string + end_date: + title: End Date + type: string + HTTPValidationError: + title: HTTPValidationError + type: object + properties: + detail: + title: Detail + type: array + items: + $ref: "#/components/schemas/ValidationError" + Query: + title: Query + required: + - query + type: object + properties: + query: + title: Query + type: string + filter: + $ref: "#/components/schemas/DocumentMetadataFilter" + top_k: + title: Top K + type: integer + default: 3 + QueryRequest: + title: QueryRequest + required: + - queries + type: object + properties: + queries: + title: Queries + type: array + items: + $ref: "#/components/schemas/Query" + QueryResponse: + title: QueryResponse + required: + - results + type: object + properties: + results: + title: Results + type: array + items: + $ref: "#/components/schemas/QueryResult" + QueryResult: + title: QueryResult + required: + - query + - results + type: object + properties: + query: + title: Query + type: string + results: + title: Results + type: array + items: + $ref: "#/components/schemas/DocumentChunkWithScore" + Source: + title: Source + enum: + - email + - file + - chat + type: string + description: An enumeration. + UpsertRequest: + title: UpsertRequest + required: + - documents + type: object + properties: + documents: + title: Documents + type: array + items: + $ref: "#/components/schemas/Document" + UpsertResponse: + title: UpsertResponse + required: + - ids + type: object + properties: + ids: + title: Ids + type: array + items: + type: string + ValidationError: + title: ValidationError + required: + - loc + - msg + - type + type: object + properties: + loc: + title: Location + type: array + items: + anyOf: + - type: string + - type: integer + msg: + title: Message + type: string + type: + title: Error Type + type: string + securitySchemes: + HTTPBearer: + type: http + scheme: bearer diff --git a/examples/providers/elasticsearch/search.ipynb b/examples/providers/elasticsearch/search.ipynb new file mode 100644 index 000000000..31768262d --- /dev/null +++ b/examples/providers/elasticsearch/search.ipynb @@ -0,0 +1,724 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Elasticsearch as a datastore\n", + "\n", + "In this walkthrough we will see how to use the retrieval API with a Elasticsearch datastore for *search / question-answering*.\n", + "\n", + "Before running this notebook you should have already initialized the retrieval API and have it running locally or elsewhere. See readme for instructions on how to do this." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## App Quickstart" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Install Python 3.10 if not already installed.\n", + "\n", + "2. Clone the `retrieval-app` repository:\n", + "\n", + "```\n", + "git clone git@github.com:openai/retrieval-app.git\n", + "```\n", + "\n", + "3. Navigate to the app directory:\n", + "\n", + "```\n", + "cd /path/to/retrieval-app\n", + "```\n", + "\n", + "4. Install `poetry`:\n", + "\n", + "```\n", + "pip install poetry\n", + "```\n", + "\n", + "5. Create a new virtual environment:\n", + "\n", + "```\n", + "poetry env use python3.10\n", + "```\n", + "\n", + "6. Install the `retrieval-app` dependencies:\n", + "\n", + "```\n", + "poetry install\n", + "```\n", + "\n", + "7. Set app environment variables:\n", + "\n", + "* `BEARER_TOKEN`: Secret token used by the app to authorize incoming requests. We will later include this in the request `headers`. The token can be generated however you prefer, such as using [jwt.io](https://jwt.io/).\n", + "\n", + "* `OPENAI_API_KEY`: The OpenAI API key used for generating embeddings with the `text-embedding-ada-002` model. [Get an API key here](https://platform.openai.com/account/api-keys)!\n", + "\n", + "8. Set Elasticsearch-specific environment variables:\n", + "\n", + "* `DATASTORE`: set to `elasticsearch`.\n", + "\n", + "9. Set the Elasticsearch connection specific environment variables. Either set `ELASTICSEARCH_CLOUD_ID` or `ELASTICSEARCH_URL`.\n", + "* `ELASTICSEARCH_CLOUD_ID`: Set to your deployment cloud id. You can find this in the [Elasticsearch console](https://cloud.elastic.co).\n", + "\n", + "* `ELASTICSEARCH_URL`: Set to your Elasticsearch URL, looks like `https://:@:`. You can find this in the [Elasticsearch console](https://cloud.elastic.co).\n", + "\n", + "10. Set the Elasticsearch authentication specific environment variables. Either set `ELASTICSEARCH_USERNAME` and `ELASTICSEARCH_PASSWORD` or `ELASTICSEARCH_API_KEY`.\n", + "\n", + "* `ELASTICSEARCH_USERNAME`: Set to your Elasticsearch username. You can find this in the [Elasticsearch console](https://cloud.elastic.co). Typically this is set to `elastic`.\n", + "\n", + "* `ELASTICSEARCH_PASSWORD`: Set to your Elasticsearch password. You can find this in the [Elasticsearch console](https://cloud.elastic.co) in security.\n", + "\n", + "* `ELASTICSEARCH_API_KEY`: Set to your Elasticsearch API key. You can set one up in Kibana Stack management page.\n", + "\n", + "11. Set the Elasticsearch index specific environment variables.\n", + "\n", + "* `ELASTICSEARCH_INDEX`: Set to the name of the Elasticsearch index you want to use.\n", + "\n", + "12. Run the app with:\n", + "\n", + "```\n", + "poetry run start\n", + "```\n", + "\n", + "If running the app locally you should see something like:\n", + "\n", + "```\n", + "INFO: Uvicorn running on http://0.0.0.0:8000\n", + "INFO: Application startup complete.\n", + "```\n", + "\n", + "In that case, the app is automatically connected to our index (specified by `ELASTICSEARCH_INDEX`), if no index with that name existed beforehand, the app creates one for us.\n", + "\n", + "Now we're ready to move on to populating our index with some data." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Required Libraries" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are a few Python libraries we must `pip install` for this notebook to run, those are:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.2.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], + "source": [ + "!pip install -qU datasets pandas tqdm" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preparing Data" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use the **S**tanford **Qu**estion **A**nswering **D**ataset (SQuAD2), which we download from Hugging Face Datasets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from datasets import load_dataset\n", + "\n", + "data = load_dataset(\"squad_v2\", split=\"train\")\n", + "data" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Transform the data into a Pandas dataframe for simpler preprocessing." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecontextquestionanswers
056be85543aeaaa14008c9063BeyoncéBeyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b...When did Beyonce start becoming popular?{'text': ['in the late 1990s'], 'answer_start'...
156be85543aeaaa14008c9065BeyoncéBeyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b...What areas did Beyonce compete in when she was...{'text': ['singing and dancing'], 'answer_star...
256be85543aeaaa14008c9066BeyoncéBeyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b...When did Beyonce leave Destiny's Child and bec...{'text': ['2003'], 'answer_start': [526]}
356bf6b0f3aeaaa14008c9601BeyoncéBeyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b...In what city and state did Beyonce grow up?{'text': ['Houston, Texas'], 'answer_start': [...
456bf6b0f3aeaaa14008c9602BeyoncéBeyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b...In which decade did Beyonce become famous?{'text': ['late 1990s'], 'answer_start': [276]}
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 56be85543aeaaa14008c9063 Beyoncé \n", + "1 56be85543aeaaa14008c9065 Beyoncé \n", + "2 56be85543aeaaa14008c9066 Beyoncé \n", + "3 56bf6b0f3aeaaa14008c9601 Beyoncé \n", + "4 56bf6b0f3aeaaa14008c9602 Beyoncé \n", + "\n", + " context \\\n", + "0 Beyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b... \n", + "1 Beyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b... \n", + "2 Beyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b... \n", + "3 Beyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b... \n", + "4 Beyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b... \n", + "\n", + " question \\\n", + "0 When did Beyonce start becoming popular? \n", + "1 What areas did Beyonce compete in when she was... \n", + "2 When did Beyonce leave Destiny's Child and bec... \n", + "3 In what city and state did Beyonce grow up? \n", + "4 In which decade did Beyonce become famous? \n", + "\n", + " answers \n", + "0 {'text': ['in the late 1990s'], 'answer_start'... \n", + "1 {'text': ['singing and dancing'], 'answer_star... \n", + "2 {'text': ['2003'], 'answer_start': [526]} \n", + "3 {'text': ['Houston, Texas'], 'answer_start': [... \n", + "4 {'text': ['late 1990s'], 'answer_start': [276]} " + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = data.to_pandas()\n", + "data.head()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The dataset contains a lot of duplicate `context` paragraphs, this is because each `context` can have many relevant questions. We don't want these duplicates so we remove like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "19029\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecontextquestionanswers
056be85543aeaaa14008c9063BeyoncéBeyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b...When did Beyonce start becoming popular?{'text': ['in the late 1990s'], 'answer_start'...
1556be86cf3aeaaa14008c9076BeyoncéFollowing the disbandment of Destiny's Child i...After her second solo album, what other entert...{'text': ['acting'], 'answer_start': [207]}
2756be88473aeaaa14008c9080BeyoncéA self-described \"modern-day feminist\", Beyonc...In her music, what are some recurring elements...{'text': ['love, relationships, and monogamy']...
3956be892d3aeaaa14008c908bBeyoncéBeyoncé Giselle Knowles was born in Houston, T...Beyonce's younger sibling also sang with her i...{'text': ['Destiny's Child'], 'answer_start': ...
5256be8a583aeaaa14008c9094BeyoncéBeyoncé attended St. Mary's Elementary School ...What town did Beyonce go to school in?{'text': ['Fredericksburg'], 'answer_start': [...
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 56be85543aeaaa14008c9063 Beyoncé \n", + "15 56be86cf3aeaaa14008c9076 Beyoncé \n", + "27 56be88473aeaaa14008c9080 Beyoncé \n", + "39 56be892d3aeaaa14008c908b Beyoncé \n", + "52 56be8a583aeaaa14008c9094 Beyoncé \n", + "\n", + " context \\\n", + "0 Beyoncé Giselle Knowles-Carter (/biːˈjɒnseɪ/ b... \n", + "15 Following the disbandment of Destiny's Child i... \n", + "27 A self-described \"modern-day feminist\", Beyonc... \n", + "39 Beyoncé Giselle Knowles was born in Houston, T... \n", + "52 Beyoncé attended St. Mary's Elementary School ... \n", + "\n", + " question \\\n", + "0 When did Beyonce start becoming popular? \n", + "15 After her second solo album, what other entert... \n", + "27 In her music, what are some recurring elements... \n", + "39 Beyonce's younger sibling also sang with her i... \n", + "52 What town did Beyonce go to school in? \n", + "\n", + " answers \n", + "0 {'text': ['in the late 1990s'], 'answer_start'... \n", + "15 {'text': ['acting'], 'answer_start': [207]} \n", + "27 {'text': ['love, relationships, and monogamy']... \n", + "39 {'text': ['Destiny's Child'], 'answer_start': ... \n", + "52 {'text': ['Fredericksburg'], 'answer_start': [... " + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = data.drop_duplicates(subset=[\"context\"])\n", + "print(len(data))\n", + "data.head()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The format required by the apps `upsert` function is a list of documents like:\n", + "\n", + "```json\n", + "[\n", + " {\n", + " \"id\": \"abc\",\n", + " \"text\": \"some important document text\",\n", + " \"metadata\": {\n", + " \"field1\": \"optional metadata goes here\",\n", + " \"field2\": 54\n", + " }\n", + " },\n", + " {\n", + " \"id\": \"123\",\n", + " \"text\": \"some other important text\",\n", + " \"metadata\": {\n", + " \"field1\": \"another metadata\",\n", + " \"field2\": 71,\n", + " \"field3\": \"not all metadatas need the same structure\"\n", + " }\n", + " }\n", + " ...\n", + "]\n", + "```\n", + "\n", + "Every document *must* have a `\"text\"` field. The `\"id\"` and `\"metadata\"` fields are optional.\n", + "\n", + "To create this format for our SQuAD data we do:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "documents = [\n", + " {\n", + " 'id': r['id'],\n", + " 'text': r['context'],\n", + " 'metadata': {\n", + " 'title': r['title']\n", + " }\n", + " } for r in data.to_dict(orient='records')\n", + "]\n", + "documents[:3]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Indexing the Docs" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, it's time to initiate the indexing process, also known as upserting, for our documents. To perform these requests to the retrieval app API, we must provide authorization using the BEARER_TOKEN we defined earlier. Below is how we accomplish this:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "BEARER_TOKEN = os.environ.get(\"BEARER_TOKEN\") or \"BEARER_TOKEN_HERE\"\n", + "\n", + "headers = {\n", + " \"Authorization\": f\"Bearer {BEARER_TOKEN}\"\n", + "}" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will execute bulk inserts in batches set by the `batch_size`.\n", + "\n", + "Now that all our SQuAD2 records have been successfully indexed, we can proceed with the querying phase." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 1/1 [00:16<00:00, 16.88s/it]\n" + ] + } + ], + "source": [ + "from tqdm.auto import tqdm\n", + "import requests\n", + "from requests.adapters import HTTPAdapter, Retry\n", + "\n", + "batch_size = 100\n", + "endpoint_url = \"http://localhost:8000\"\n", + "s = requests.Session()\n", + "\n", + "# we setup a retry strategy to retry on 5xx errors\n", + "retries = Retry(\n", + " total=5, # number of retries before raising error\n", + " backoff_factor=0.1,\n", + " status_forcelist=[500, 502, 503, 504]\n", + ")\n", + "s.mount('http://', HTTPAdapter(max_retries=retries))\n", + "\n", + "for i in tqdm(range(0, 10, batch_size)):\n", + " i_end = min(len(documents), i+batch_size)\n", + " # make post request that allows up to 5 retries\n", + " res = s.post(\n", + " f\"{endpoint_url}/upsert\",\n", + " headers=headers,\n", + " json={\n", + " \"documents\": documents[i:i_end]\n", + " }\n", + " )" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Making Queries" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By passing one or more queries to the /query endpoint, we can easily conduct a query on the datastore. For this task, we can utilize a few questions from SQuAD2." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "19029" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "queries = data['question'].tolist()\n", + "# format into the structure needed by the /query endpoint\n", + "queries = [{'query': queries[i]} for i in range(len(queries))]\n", + "len(queries)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res = requests.post(\n", + " \"http://0.0.0.0:8000/query\",\n", + " headers=headers,\n", + " json={\n", + " 'queries': queries[:3]\n", + " }\n", + ")\n", + "res" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At this point, we have the ability to iterate through the responses and observe the outcomes obtained for each query:" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "----------------------------------------------------------------------\n", + "When did Beyonce start becoming popular?\n", + "\n", + "0.93: On December 13, 2013, Beyoncé unexpectedly released her eponymous fifth studio album on the iTunes Store without any prior announcement or promotion. The album debuted atop the Billboard 200 chart, giving Beyoncé her fifth consecutive number-one album in the US. This made her the first woman in the chart's history to have her first five studio albums debut at number one. Beyoncé received critical acclaim and commercial success, selling one million digital copies worldwide in six days; The New York Times noted the album's unconventional, unexpected release as significant. Musically an electro-R&B album, it concerns darker themes previously unexplored in her work, such as \"bulimia, postnatal depression [and] the fears and insecurities of marriage and motherhood\". The single \"Drunk in Love\", featuring Jay Z, peaked at number two on the Billboard Hot 100 chart.\n", + "0.93: Beyoncé's first solo recording was a feature on Jay Z's \"'03 Bonnie & Clyde\" that was released in October 2002, peaking at number four on the U.S. Billboard Hot 100 chart. Her first solo album Dangerously in Love was released on June 24, 2003, after Michelle Williams and Kelly Rowland had released their solo efforts. The album sold 317,000 copies in its first week, debuted atop the Billboard 200, and has since sold 11 million copies worldwide. The album's lead single, \"Crazy in Love\", featuring Jay Z, became Beyoncé's first number-one single as a solo artist in the US. The single \"Baby Boy\" also reached number one, and singles, \"Me, Myself and I\" and \"Naughty Girl\", both reached the top-five.\n", + "0.93: Beyoncé is believed to have first started a relationship with Jay Z after a collaboration on \"'03 Bonnie & Clyde\", which appeared on his seventh album The Blueprint 2: The Gift & The Curse (2002). Beyoncé appeared as Jay Z's girlfriend in the music video for the song, which would further fuel speculation of their relationship. On April 4, 2008, Beyoncé and Jay Z were married without publicity. As of April 2014, the couple have sold a combined 300 million records together. The couple are known for their private relationship, although they have appeared to become more relaxed in recent years. Beyoncé suffered a miscarriage in 2010 or 2011, describing it as \"the saddest thing\" she had ever endured. She returned to the studio and wrote music in order to cope with the loss.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n", + "----------------------------------------------------------------------\n", + "After her second solo album, what other entertainment venture did Beyonce explore?\n", + "\n", + "0.93: Following the disbandment of Destiny's Child in June 2005, she released her second solo album, B'Day (2006), which contained hits \"Déjà Vu\", \"Irreplaceable\", and \"Beautiful Liar\". Beyoncé also ventured into acting, with a Golden Globe-nominated performance in Dreamgirls (2006), and starring roles in The Pink Panther (2006) and Obsessed (2009). Her marriage to rapper Jay Z and portrayal of Etta James in Cadillac Records (2008) influenced her third album, I Am... Sasha Fierce (2008), which saw the birth of her alter-ego Sasha Fierce and earned a record-setting six Grammy Awards in 2010, including Song of the Year for \"Single Ladies (Put a Ring on It)\".\n", + "0.92: Beyoncé announced a hiatus from her music career in January 2010, heeding her mother's advice, \"to live life, to be inspired by things again\". During the break she and her father parted ways as business partners. Beyoncé's musical break lasted nine months and saw her visit multiple European cities, the Great Wall of China, the Egyptian pyramids, Australia, English music festivals and various museums and ballet performances.\n", + "0.92: Beyoncé took a hiatus from music in 2010 and took over management of her career; her fourth album 4 (2011) was subsequently mellower in tone, exploring 1970s funk, 1980s pop, and 1990s soul. Her critically acclaimed fifth studio album, Beyoncé (2013), was distinguished from previous releases by its experimental production and exploration of darker themes.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n", + "----------------------------------------------------------------------\n", + "In her music, what are some recurring elements in them?\n", + "\n", + "0.91: Beyoncé's music is generally R&B, but she also incorporates pop, soul and funk into her songs. 4 demonstrated Beyoncé's exploration of 90s-style R&B, as well as further use of soul and hip hop than compared to previous releases. While she almost exclusively releases English songs, Beyoncé recorded several Spanish songs for Irreemplazable (re-recordings of songs from B'Day for a Spanish-language audience), and the re-release of B'Day. To record these, Beyoncé was coached phonetically by American record producer Rudy Perez.\n", + "0.9: The feminism and female empowerment themes on Beyoncé's second solo album B'Day were inspired by her role in Dreamgirls and by singer Josephine Baker. Beyoncé paid homage to Baker by performing \"Déjà Vu\" at the 2006 Fashion Rocks concert wearing Baker's trademark mini-hula skirt embellished with fake bananas. Beyoncé's third solo album I Am... Sasha Fierce was inspired by Jay Z and especially by Etta James, whose \"boldness\" inspired Beyoncé to explore other musical genres and styles. Her fourth solo album, 4, was inspired by Fela Kuti, 1990s R&B, Earth, Wind & Fire, DeBarge, Lionel Richie, Teena Marie with additional influences by The Jackson 5, New Edition, Adele, Florence and the Machine, and Prince.\n", + "0.9: She has received co-writing credits for most of the songs recorded with Destiny's Child and her solo efforts. Her early songs were personally driven and female-empowerment themed compositions like \"Independent Women\" and \"Survivor\", but after the start of her relationship with Jay Z she transitioned to more man-tending anthems such as \"Cater 2 U\". Beyoncé has also received co-producing credits for most of the records in which she has been involved, especially during her solo efforts. However, she does not formulate beats herself, but typically comes up with melodies and ideas during production, sharing them with producers.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n" + ] + } + ], + "source": [ + "for query_result in res.json()['results']:\n", + " query = query_result['query']\n", + " answers = []\n", + " scores = []\n", + " for result in query_result['results']:\n", + " answers.append(result['text'])\n", + " scores.append(round(result['score'], 2))\n", + " print(\"-\"*70+\"\\n\"+query+\"\\n\\n\"+\"\\n\".join([f\"{s}: {a}\" for a, s in zip(answers, scores)])+\"\\n\"+\"-\"*70+\"\\n\\n\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The top results are all relevant as we would have hoped. We can see that the `score` is a measure of how relevant the document is to the query. The higher the score the more relevant the document is to the query." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "chatgpt-retrieval-plugin-S7h-2AWq-py3.10", + "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.3" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "1979a773a5778de9a5fa593a629dff0ab3c80c2563810d3e6a8dfb123dc01c7d" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/providers/pinecone/semantic-search.ipynb b/examples/providers/pinecone/semantic-search.ipynb new file mode 100644 index 000000000..de54be1ac --- /dev/null +++ b/examples/providers/pinecone/semantic-search.ipynb @@ -0,0 +1,809 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using the Pinecone Retrieval App\n", + "\n", + "In this walkthrough we will see how to use the retrieval API with a Pinecone datastore for *semantic search / question-answering*.\n", + "\n", + "Before running this notebook you should have already initialized the retrieval API and have it running locally or elsewhere. The full instructions for doing this are found in the [project README]().\n", + "\n", + "We will summarize the instructions (specific to the Pinecone datastore) before moving on to the walkthrough." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## App Quickstart" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Install Python 3.10 if not already installed.\n", + "\n", + "2. Clone the `retrieval-app` repository:\n", + "\n", + "```\n", + "git clone git@github.com:openai/retrieval-app.git\n", + "```\n", + "\n", + "3. Navigate to the app directory:\n", + "\n", + "```\n", + "cd /path/to/retrieval-app\n", + "```\n", + "\n", + "4. Install `poetry`:\n", + "\n", + "```\n", + "pip install poetry\n", + "```\n", + "\n", + "5. Create a new virtual environment:\n", + "\n", + "```\n", + "poetry env use python3.10\n", + "```\n", + "\n", + "6. Install the `retrieval-app` dependencies:\n", + "\n", + "```\n", + "poetry install\n", + "```\n", + "\n", + "7. Set app environment variables:\n", + "\n", + "* `BEARER_TOKEN`: Secret token used by the app to authorize incoming requests. We will later include this in the request `headers`. The token can be generated however you prefer, such as using [jwt.io](https://jwt.io/).\n", + "\n", + "* `OPENAI_API_KEY`: The OpenAI API key used for generating embeddings with the `text-embedding-ada-002` model. [Get an API key here](https://platform.openai.com/account/api-keys)!\n", + "\n", + "8. Set Pinecone-specific environment variables:\n", + "\n", + "* `DATASTORE`: set to `pinecone`.\n", + "\n", + "* `PINECONE_API_KEY`: Set to your Pinecone API key. This requires a free Pinecone account and can be [found in the Pinecone console](https://app.pinecone.io/).\n", + "\n", + "* `PINECONE_ENVIRONMENT`: Set to your Pinecone environment, looks like `us-east1-gcp`, `us-west1-aws`, and can be found next to your API key in the [Pinecone console](https://app.pinecone.io/).\n", + "\n", + "* `PINECONE_INDEX`: Set this to your chosen index name. The name you choose is your choice, we just recommend setting it to something descriptive like `\"openai-retrieval-app\"`. *Note that index names are restricted to alphanumeric characters, `\"-\"`, and can contain a maximum of 45 characters.*\n", + "\n", + "8. Run the app with:\n", + "\n", + "```\n", + "poetry run start\n", + "```\n", + "\n", + "If running the app locally you should see something like:\n", + "\n", + "```\n", + "INFO: Uvicorn running on http://0.0.0.0:8000\n", + "INFO: Application startup complete.\n", + "```\n", + "\n", + "In that case, the app is automatically connected to our index (specified by `PINECONE_INDEX`), if no index with that name existed beforehand, the app creates one for us.\n", + "\n", + "Now we're ready to move on to populating our index with some data." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Required Libraries" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are a few Python libraries we must `pip install` for this notebook to run, those are:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install -qU datasets pandas tqdm" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preparing Data" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use the **S**tanford **Qu**estion **A**nswering **D**ataset (SQuAD), which we download from Hugging Face Datasets." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Found cached dataset squad (/Users/jamesbriggs/.cache/huggingface/datasets/squad/plain_text/1.0.0/d6ec3ceb99ca480ce37cdd35555d6cb2511d223b9150cce08a837ef62ffea453)\n" + ] + }, + { + "data": { + "text/plain": [ + "Dataset({\n", + " features: ['id', 'title', 'context', 'question', 'answers'],\n", + " num_rows: 87599\n", + "})" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from datasets import load_dataset\n", + "\n", + "data = load_dataset(\"squad\", split=\"train\")\n", + "data" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Convert to Pandas dataframe for easier preprocessing steps." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecontextquestionanswers
05733be284776f41900661182University_of_Notre_DameArchitecturally, the school has a Catholic cha...To whom did the Virgin Mary allegedly appear i...{'text': ['Saint Bernadette Soubirous'], 'answ...
15733be284776f4190066117fUniversity_of_Notre_DameArchitecturally, the school has a Catholic cha...What is in front of the Notre Dame Main Building?{'text': ['a copper statue of Christ'], 'answe...
25733be284776f41900661180University_of_Notre_DameArchitecturally, the school has a Catholic cha...The Basilica of the Sacred heart at Notre Dame...{'text': ['the Main Building'], 'answer_start'...
35733be284776f41900661181University_of_Notre_DameArchitecturally, the school has a Catholic cha...What is the Grotto at Notre Dame?{'text': ['a Marian place of prayer and reflec...
45733be284776f4190066117eUniversity_of_Notre_DameArchitecturally, the school has a Catholic cha...What sits on top of the Main Building at Notre...{'text': ['a golden statue of the Virgin Mary'...
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 5733be284776f41900661182 University_of_Notre_Dame \n", + "1 5733be284776f4190066117f University_of_Notre_Dame \n", + "2 5733be284776f41900661180 University_of_Notre_Dame \n", + "3 5733be284776f41900661181 University_of_Notre_Dame \n", + "4 5733be284776f4190066117e University_of_Notre_Dame \n", + "\n", + " context \\\n", + "0 Architecturally, the school has a Catholic cha... \n", + "1 Architecturally, the school has a Catholic cha... \n", + "2 Architecturally, the school has a Catholic cha... \n", + "3 Architecturally, the school has a Catholic cha... \n", + "4 Architecturally, the school has a Catholic cha... \n", + "\n", + " question \\\n", + "0 To whom did the Virgin Mary allegedly appear i... \n", + "1 What is in front of the Notre Dame Main Building? \n", + "2 The Basilica of the Sacred heart at Notre Dame... \n", + "3 What is the Grotto at Notre Dame? \n", + "4 What sits on top of the Main Building at Notre... \n", + "\n", + " answers \n", + "0 {'text': ['Saint Bernadette Soubirous'], 'answ... \n", + "1 {'text': ['a copper statue of Christ'], 'answe... \n", + "2 {'text': ['the Main Building'], 'answer_start'... \n", + "3 {'text': ['a Marian place of prayer and reflec... \n", + "4 {'text': ['a golden statue of the Virgin Mary'... " + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = data.to_pandas()\n", + "data.head()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The dataset contains a lot of duplicate `context` paragraphs, this is because each `context` can have many relevant questions. We don't want these duplicates so we remove like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "18891\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecontextquestionanswers
05733be284776f41900661182University_of_Notre_DameArchitecturally, the school has a Catholic cha...To whom did the Virgin Mary allegedly appear i...{'text': ['Saint Bernadette Soubirous'], 'answ...
55733bf84d058e614000b61beUniversity_of_Notre_DameAs at most other universities, Notre Dame's st...When did the Scholastic Magazine of Notre dame...{'text': ['September 1876'], 'answer_start': [...
105733bed24776f41900661188University_of_Notre_DameThe university is the major seat of the Congre...Where is the headquarters of the Congregation ...{'text': ['Rome'], 'answer_start': [119]}
155733a6424776f41900660f51University_of_Notre_DameThe College of Engineering was established in ...How many BS level degrees are offered in the C...{'text': ['eight'], 'answer_start': [487]}
205733a70c4776f41900660f64University_of_Notre_DameAll of Notre Dame's undergraduate students are...What entity provides help with the management ...{'text': ['Learning Resource Center'], 'answer...
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 5733be284776f41900661182 University_of_Notre_Dame \n", + "5 5733bf84d058e614000b61be University_of_Notre_Dame \n", + "10 5733bed24776f41900661188 University_of_Notre_Dame \n", + "15 5733a6424776f41900660f51 University_of_Notre_Dame \n", + "20 5733a70c4776f41900660f64 University_of_Notre_Dame \n", + "\n", + " context \\\n", + "0 Architecturally, the school has a Catholic cha... \n", + "5 As at most other universities, Notre Dame's st... \n", + "10 The university is the major seat of the Congre... \n", + "15 The College of Engineering was established in ... \n", + "20 All of Notre Dame's undergraduate students are... \n", + "\n", + " question \\\n", + "0 To whom did the Virgin Mary allegedly appear i... \n", + "5 When did the Scholastic Magazine of Notre dame... \n", + "10 Where is the headquarters of the Congregation ... \n", + "15 How many BS level degrees are offered in the C... \n", + "20 What entity provides help with the management ... \n", + "\n", + " answers \n", + "0 {'text': ['Saint Bernadette Soubirous'], 'answ... \n", + "5 {'text': ['September 1876'], 'answer_start': [... \n", + "10 {'text': ['Rome'], 'answer_start': [119]} \n", + "15 {'text': ['eight'], 'answer_start': [487]} \n", + "20 {'text': ['Learning Resource Center'], 'answer... " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = data.drop_duplicates(subset=[\"context\"])\n", + "print(len(data))\n", + "data.head()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The format required by the apps `upsert` function is a list of documents like:\n", + "\n", + "```json\n", + "[\n", + " {\n", + " \"id\": \"abc\",\n", + " \"text\": \"some important document text\",\n", + " \"metadata\": {\n", + " \"field1\": \"optional metadata goes here\",\n", + " \"field2\": 54\n", + " }\n", + " },\n", + " {\n", + " \"id\": \"123\",\n", + " \"text\": \"some other important text\",\n", + " \"metadata\": {\n", + " \"field1\": \"another metadata\",\n", + " \"field2\": 71,\n", + " \"field3\": \"not all metadatas need the same structure\"\n", + " }\n", + " }\n", + " ...\n", + "]\n", + "```\n", + "\n", + "Every document *must* have a `\"text\"` field. The `\"id\"` and `\"metadata\"` fields are optional.\n", + "\n", + "To create this format for our SQuAD data we do:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'id': '5733be284776f41900661182',\n", + " 'text': 'Architecturally, the school has a Catholic character. Atop the Main Building\\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend \"Venite Ad Me Omnes\". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.',\n", + " 'metadata': {'title': 'University_of_Notre_Dame'}},\n", + " {'id': '5733bf84d058e614000b61be',\n", + " 'text': \"As at most other universities, Notre Dame's students run a number of news media outlets. The nine student-run outlets include three newspapers, both a radio and television station, and several magazines and journals. Begun as a one-page journal in September 1876, the Scholastic magazine is issued twice monthly and claims to be the oldest continuous collegiate publication in the United States. The other magazine, The Juggler, is released twice a year and focuses on student literature and artwork. The Dome yearbook is published annually. The newspapers have varying publication interests, with The Observer published daily and mainly reporting university and other news, and staffed by students from both Notre Dame and Saint Mary's College. Unlike Scholastic and The Dome, The Observer is an independent publication and does not have a faculty advisor or any editorial oversight from the University. In 1987, when some students believed that The Observer began to show a conservative bias, a liberal newspaper, Common Sense was published. Likewise, in 2003, when other students believed that the paper showed a liberal bias, the conservative paper Irish Rover went into production. Neither paper is published as often as The Observer; however, all three are distributed to all students. Finally, in Spring 2008 an undergraduate journal for political science research, Beyond Politics, made its debut.\",\n", + " 'metadata': {'title': 'University_of_Notre_Dame'}},\n", + " {'id': '5733bed24776f41900661188',\n", + " 'text': 'The university is the major seat of the Congregation of Holy Cross (albeit not its official headquarters, which are in Rome). Its main seminary, Moreau Seminary, is located on the campus across St. Joseph lake from the Main Building. Old College, the oldest building on campus and located near the shore of St. Mary lake, houses undergraduate seminarians. Retired priests and brothers reside in Fatima House (a former retreat center), Holy Cross House, as well as Columba Hall near the Grotto. The university through the Moreau Seminary has ties to theologian Frederick Buechner. While not Catholic, Buechner has praised writers from Notre Dame and Moreau Seminary created a Buechner Prize for Preaching.',\n", + " 'metadata': {'title': 'University_of_Notre_Dame'}}]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "documents = [\n", + " {\n", + " 'id': r['id'],\n", + " 'text': r['context'],\n", + " 'metadata': {\n", + " 'title': r['title']\n", + " }\n", + " } for r in data.to_dict(orient='records')\n", + "]\n", + "documents[:3]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Indexing the Docs" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We're now ready to begin indexing (or *upserting*) our `documents`. To make these requests to the retrieval app API, we will need to provide authorization in the form of the `BEARER_TOKEN` we set earlier. We do this below:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "BEARER_TOKEN = os.environ.get(\"BEARER_TOKEN\") or \"BEARER_TOKEN_HERE\"" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the `BEARER_TOKEN` to create our authorization `headers`:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "headers = {\n", + " \"Authorization\": f\"Bearer {BEARER_TOKEN}\"\n", + "}" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll perform the upsert in batches of `batch_size`. Make sure that the `endpoint_url` variable is set to the correct location for your running *retrieval-app* API." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8694da67455d4bb78cc778e49f69a872", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/10 [00:00" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res = requests.post(\n", + " \"http://0.0.0.0:8000/query\",\n", + " headers=headers,\n", + " json={\n", + " 'queries': queries[:3]\n", + " }\n", + ")\n", + "res" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can loop through the responses and see the results returned for each query:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "----------------------------------------------------------------------\n", + "To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?\n", + "\n", + "0.83: Architecturally, the school has a Catholic character. Atop the Main Building's gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend \"Venite Ad Me Omnes\". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.\n", + "0.81: Within the white inescutcheon, the five quinas (small blue shields) with their five white bezants representing the five wounds of Christ (Portuguese: Cinco Chagas) when crucified and are popularly associated with the \"Miracle of Ourique\". The story associated with this miracle tells that before the Battle of Ourique (25 July 1139), an old hermit appeared before Count Afonso Henriques (future Afonso I) as a divine messenger. He foretold Afonso's victory and assured him that God was watching over him and his peers. The messenger advised him to walk away from his camp, alone, if he heard a nearby chapel bell tolling, in the following night. In doing so, he witnessed an apparition of Jesus on the cross. Ecstatic, Afonso heard Jesus promising victories for the coming battles, as well as God's wish to act through Afonso, and his descendants, in order to create an empire which would carry His name to unknown lands, thus choosing the Portuguese to perform great tasks.\n", + "0.79: In 1842, the Bishop of Vincennes, Célestine Guynemer de la Hailandière, offered land to Father Edward Sorin of the Congregation of the Holy Cross, on the condition that he build a college in two years. Fr. Sorin arrived on the site with eight Holy Cross brothers from France and Ireland on November 26, 1842, and began the school using Father Stephen Badin's old log chapel. He soon erected additional buildings, including Old College, the first church, and the first main building. They immediately acquired two students and set about building additions to the campus.\n", + "0.79: Because of its Catholic identity, a number of religious buildings stand on campus. The Old College building has become one of two seminaries on campus run by the Congregation of Holy Cross. The current Basilica of the Sacred Heart is located on the spot of Fr. Sorin's original church, which became too small for the growing college. It is built in French Revival style and it is decorated by stained glass windows imported directly from France. The interior was painted by Luigi Gregori, an Italian painter invited by Fr. Sorin to be artist in residence. The Basilica also features a bell tower with a carillon. Inside the church there are also sculptures by Ivan Mestrovic. The Grotto of Our Lady of Lourdes, which was built in 1896, is a replica of the original in Lourdes, France. It is very popular among students and alumni as a place of prayer and meditation, and it is considered one of the most beloved spots on campus.\n", + "0.78: The funeral, held at the Church of the Madeleine in Paris, was delayed almost two weeks, until 30 October. Entrance was restricted to ticket holders as many people were expected to attend. Over 3,000 people arrived without invitations, from as far as London, Berlin and Vienna, and were excluded.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n", + "----------------------------------------------------------------------\n", + "When did the Scholastic Magazine of Notre dame begin publishing?\n", + "\n", + "0.88: As at most other universities, Notre Dame's students run a number of news media outlets. The nine student-run outlets include three newspapers, both a radio and television station, and several magazines and journals. Begun as a one-page journal in September 1876, the Scholastic magazine is issued twice monthly and claims to be the oldest continuous collegiate publication in the United States. The other magazine, The Juggler, is released twice a year and focuses on student literature and artwork. The Dome yearbook is published annually. The newspapers have varying publication interests, with The Observer published daily and mainly reporting university and other news, and staffed by students from both Notre Dame and Saint Mary's College. Unlike Scholastic and The Dome, The Observer is an independent publication and does not have a faculty advisor or any editorial oversight from the University. In 1987, when some students believed that The Observer began to show a conservative bias, a liberal newspaper, Common Sense was published. Likewise, in 2003, when other students believed that the paper showed a liberal bias, the conservative paper Irish Rover went into production. Neither paper is published as often as The Observer; however, all three are distributed to all students.\n", + "0.83: In 1919 Father James Burns became president of Notre Dame, and in three years he produced an academic revolution that brought the school up to national standards by adopting the elective system and moving away from the university's traditional scholastic and classical emphasis. By contrast, the Jesuit colleges, bastions of academic conservatism, were reluctant to move to a system of electives. Their graduates were shut out of Harvard Law School for that reason. Notre Dame continued to grow over the years, adding more colleges, programs, and sports teams. By 1921, with the addition of the College of Commerce, Notre Dame had grown from a small college to a university with five colleges and a professional law school. The university continued to expand and add new residence halls and buildings with each subsequent president.\n", + "0.83: The rise of Hitler and other dictators in the 1930s forced numerous Catholic intellectuals to flee Europe; president John O'Hara brought many to Notre Dame. From Germany came Anton-Hermann Chroust (1907–1982) in classics and law, and Waldemar Gurian a German Catholic intellectual of Jewish descent. Positivism dominated American intellectual life in the 1920s onward but in marked contrast, Gurian received a German Catholic education and wrote his doctoral dissertation under Max Scheler. Ivan Meštrović (1883–1962), a renowned sculptor, brought Croatian culture to campus, 1955–62. Yves Simon (1903–61), brought to ND in the 1940s the insights of French studies in the Aristotelian-Thomistic tradition of philosophy; his own teacher Jacques Maritain (1882–73) was a frequent visitor to campus.\n", + "0.82: In the 18 years under the presidency of Edward Malloy, C.S.C., (1987–2005), there was a rapid growth in the school's reputation, faculty, and resources. He increased the faculty by more than 500 professors; the academic quality of the student body has improved dramatically, with the average SAT score rising from 1240 to 1360; the number of minority students more than doubled; the endowment grew from $350 million to more than $3 billion; the annual operating budget rose from $177 million to more than $650 million; and annual research funding improved from $15 million to more than $70 million. Notre Dame's most recent[when?] capital campaign raised $1.1 billion, far exceeding its goal of $767 million, and is the largest in the history of Catholic higher education.\n", + "0.82: The Rev. John J. Cavanaugh, C.S.C. served as president from 1946 to 1952. Cavanaugh's legacy at Notre Dame in the post-war years was devoted to raising academic standards and reshaping the university administration to suit it to an enlarged educational mission and an expanded student body and stressing advanced studies and research at a time when Notre Dame quadrupled in student census, undergraduate enrollment increased by more than half, and graduate student enrollment grew fivefold. Cavanaugh also established the Lobund Institute for Animal Studies and Notre Dame's Medieval Institute. Cavanaugh also presided over the construction of the Nieuwland Science Hall, Fisher Hall, and the Morris Inn, as well as the Hall of Liberal Arts (now O'Shaughnessy Hall), made possible by a donation from I.A. O'Shaughnessy, at the time the largest ever made to an American Catholic university.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n", + "----------------------------------------------------------------------\n", + "Where is the headquarters of the Congregation of the Holy Cross?\n", + "\n", + "0.88: The university is the major seat of the Congregation of Holy Cross (albeit not its official headquarters, which are in Rome). Its main seminary, Moreau Seminary, is located on the campus across St. Joseph lake from the Main Building. Old College, the oldest building on campus and located near the shore of St. Mary lake, houses undergraduate seminarians. Retired priests and brothers reside in Fatima House (a former retreat center), Holy Cross House, as well as Columba Hall near the Grotto. The university through the Moreau Seminary has ties to theologian Frederick Buechner. While not Catholic, Buechner has praised writers from Notre Dame and Moreau Seminary created a Buechner Prize for Preaching.\n", + "0.84: In 1842, the Bishop of Vincennes, Célestine Guynemer de la Hailandière, offered land to Father Edward Sorin of the Congregation of the Holy Cross, on the condition that he build a college in two years. Fr. Sorin arrived on the site with eight Holy Cross brothers from France and Ireland on November 26, 1842, and began the school using Father Stephen Badin's old log chapel. He soon erected additional buildings, including Old College, the first church, and the first main building. They immediately acquired two students and set about building additions to the campus.\n", + "0.84: Because of its Catholic identity, a number of religious buildings stand on campus. The Old College building has become one of two seminaries on campus run by the Congregation of Holy Cross. The current Basilica of the Sacred Heart is located on the spot of Fr. Sorin's original church, which became too small for the growing college. It is built in French Revival style and it is decorated by stained glass windows imported directly from France. The interior was painted by Luigi Gregori, an Italian painter invited by Fr. Sorin to be artist in residence. The Basilica also features a bell tower with a carillon. Inside the church there are also sculptures by Ivan Mestrovic. The Grotto of Our Lady of Lourdes, which was built in 1896, is a replica of the original in Lourdes, France. It is very popular among students and alumni as a place of prayer and meditation, and it is considered one of the most beloved spots on campus.\n", + "0.84: The university is affiliated with the Congregation of Holy Cross (Latin: Congregatio a Sancta Cruce, abbreviated postnominals: \"CSC\"). While religious affiliation is not a criterion for admission, more than 93% of students identify as Christian, with over 80% of the total being Catholic. Collectively, Catholic Mass is celebrated over 100 times per week on campus, and a large campus ministry program provides for the faith needs of the community. There are multitudes of religious statues and artwork around campus, most prominent of which are the statue of Mary on the Main Building, the Notre Dame Grotto, and the Word of Life mural on Hesburgh Library depicting Christ as a teacher. Additionally, every classroom displays a crucifix. There are many religious clubs (catholic and non-Catholic) at the school, including Council #1477 of the Knights of Columbus (KOC), Baptist Collegiate Ministry (BCM), Jewish Club, Muslim Student Association, Orthodox Christian Fellowship, The Mormon Club, and many more. The Notre Dame KofC are known for being the first collegiate council of KofC, operating a charitable concession stand during every home football game and owning their own building on campus which can be used as a cigar lounge.\n", + "0.83: Architecturally, the school has a Catholic character. Atop the Main Building's gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend \"Venite Ad Me Omnes\". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.\n", + "----------------------------------------------------------------------\n", + "\n", + "\n" + ] + } + ], + "source": [ + "for query_result in res.json()['results']:\n", + " query = query_result['query']\n", + " answers = []\n", + " scores = []\n", + " for result in query_result['results']:\n", + " answers.append(result['text'])\n", + " scores.append(round(result['score'], 2))\n", + " print(\"-\"*70+\"\\n\"+query+\"\\n\\n\"+\"\\n\".join([f\"{s}: {a}\" for a, s in zip(answers, scores)])+\"\\n\"+\"-\"*70+\"\\n\\n\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The top results are all relevant as we would have hoped. With that we've finished. The retrieval app API can be shut down, and to save resources the Pinecone index can be deleted within the [Pinecone console](https://app.pinecone.io/)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "chatgpt-retrieval-plugin-S7h-2AWq-py3.10", + "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.8" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "1979a773a5778de9a5fa593a629dff0ab3c80c2563810d3e6a8dfb123dc01c7d" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/providers/redis/semantic-search-and-filter.ipynb b/examples/providers/redis/semantic-search-and-filter.ipynb new file mode 100644 index 000000000..1d7b63ade --- /dev/null +++ b/examples/providers/redis/semantic-search-and-filter.ipynb @@ -0,0 +1,511 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import os\n", + "import requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Document retrieval: upsert and query basic usage\n", + "\n", + "In this walkthrough we will see how to use the retrieval API with a Redis datastore for *semantic search / question-answering*. We will also provide a basic demo showing how to use the \"filter\" function.\n", + "\n", + "Before running this notebook you should have already initialized the retrieval API and have it running locally or elsewhere. The full instructions for doing this are found in on the chatgpt-retrieval-plugin page [page](https://github.com/openai/chatgpt-retrieval-plugin#quickstart). Please follow the instructions to start the app with the redis datastore.\n", + "\n", + "Additional examples using the search features can be found [here](https://github.com/openai/chatgpt-retrieval-plugin/blob/main/examples/providers/pinecone/semantic-search.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Document\n", + "\n", + "First we will prepare a collection of documents. From the perspective of the retrieval plugin, a [document](https://github.com/openai/chatgpt-retrieval-plugin/blob/main/models/models.py) this consists\n", + "of an \"id\", \"text\" and a collection of \"metadata\".\n", + "\n", + "The \"metadata\" has \"source\", \"source_id\", \"created_at\", \"url\" and \"author\" fields. Query metadata does not expose the \"url\" field.\n", + "\n", + "The \"source\" field is an Enum and can only be one of (\"file\", \"email\" or \"chat\").\n", + "\n", + "Text is taken from company SEC 10-K filings which are in the public domain.\n", + "\n", + "For demonstration, we will insert some **fake** authors for the documents, see the respective links for the original sources. " + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "document_1 = {\n", + " \"id\": \"twtr\",\n", + " \"text\": \"\"\"Postponements, suspensions or cancellations of major events, such as sporting events\n", + " and music festivals, may lead to people perceiving the content on Twitter as less\n", + " relevant or useful or of lower quality, which could negatively affect mDAU growth,\n", + " or may reduce monetization opportunities in connection with such events.\"\"\",\n", + " \"metadata\" : {\n", + " \"source\" : \"file\",\n", + " \"source_id\" : \"test:twtr10k\",\n", + " \"created_at\": \"2020-12-31\",\n", + " \"url\": \"https://www.sec.gov/Archives/edgar/data/1418091/000141809121000031/twtr-20201231.htm\",\n", + " \"author\": 'Elvis Tusk Sr.' \n", + " }\n", + "}\n", + "\n", + "document_2 = {\n", + " \"id\": \"tsla\",\n", + " \"text\": \"\"\"Because we do not have independent dealer networks, we are responsible for delivering\n", + " all of our vehicles to our customers.\"\"\",\n", + " \"metadata\" : {\n", + " \"source\" : \"file\",\n", + " \"source_id\" : \"test:tesla10k\",\n", + " \"created_at\": \"2021-12-31\",\n", + " \"url\": \"https://www.sec.gov/Archives/edgar/data/1318605/000095017022000796/tsla-20211231.htm\",\n", + " \"author\": 'Elvis Tusk Jr.' \n", + " } \n", + "}\n", + "\n", + "document_3 = {\n", + " \"id\": \"xom\",\n", + " \"text\": \"\"\"All practical and economically-viable energy sources will need to be pursued to continue\n", + " meeting global energy demand, recognizing the scale and variety of worldwide energy needs\n", + " as well as the importance of expanding access to modern energy to promote better standards\n", + " of living for billions of people.\"\"\",\n", + " \"metadata\" : {\n", + " \"source\" : \"file\",\n", + " \"source_id\" : \"test:xom10k\",\n", + " \"created_at\": \"2020-12-31\",\n", + " \"url\": \"https://www.sec.gov/Archives/edgar/data/34088/000003408821000012/xom-20201231.htm\",\n", + " \"author\": 'Vape Jordan' \n", + " } \n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Indexing the Docs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We're now ready to begin indexing (or *upserting*) our `documents`. To make these requests to the retrieval app API, we will need to provide authorization in the form of the `BEARER_TOKEN` we set earlier. We do this below:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "BEARER_TOKEN = os.environ.get(\"BEARER_TOKEN\") or \"BEARER_TOKEN_HERE\"\n", + "endpoint_url = 'http://0.0.0.0:8000'\n", + "headers = {\n", + " \"Authorization\": f\"Bearer {BEARER_TOKEN}\"\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the `BEARER_TOKEN` to create our authorization `headers`:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "response = requests.post(\n", + " f\"{endpoint_url}/upsert\",\n", + " headers=headers,\n", + " json={\n", + " \"documents\": [document_1, document_2, document_3]\n", + " }\n", + ")\n", + "response.raise_for_status()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example filter syntax\n", + "In our example data we have tagged each companies 10k documents as a source: test:twtr10k, test:tsla10k, and test:xom10k.\n", + "And we have created **fake** authors of the documents, Elvis Tusk Jr., Elvis Tusk Sr. and Vape Jordan. We will then filter based on these fields." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "### TAG Fields\n", + "\n", + "source and source_id are \"TAG\" fields, Redis supports a limited [query syntax](https://redis.io/docs/stack/search/reference/tags/) on TAGS, which includes and \"or\" syntax, i.e. \"test:twtr10k|test:tesla10k\" or a ```*``` wildcard to match a prefix.\n", + "\n", + "In this example we have only two documents that match the filter so only two documents will show.\n", + "\n", + "Gotcha: There cannot be a space between the bar \"|\", i.e. \"test:twtr10k|test:tesla10k\" is valid, \"test:twtr10k | test:tesla10k\" is not." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'results': [{'query': 'How does Tesla deliver cars?',\n", + " 'results': [{'id': 'tsla',\n", + " 'text': 'Because we do not have independent dealer networks, we are responsible for delivering all of our vehicles to our customers.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:tesla10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/1318605/000095017022000796/tsla-20211231.htm',\n", + " 'created_at': '1640908800',\n", + " 'author': 'Elvis Tusk Jr.',\n", + " 'document_id': 'tsla'},\n", + " 'embedding': None,\n", + " 'score': 0.185401830213},\n", + " {'id': 'twtr',\n", + " 'text': 'Postponements, suspensions or cancellations of major events, such as sporting events and music festivals, may lead to people perceiving the content on Twitter as less relevant or useful or of lower quality, which could negatively affect mDAU growth, or may reduce monetization opportunities in connection with such events.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:twtr10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/1418091/000141809121000031/twtr-20201231.htm',\n", + " 'created_at': '1609372800',\n", + " 'author': 'Elvis Tusk Sr.',\n", + " 'document_id': 'twtr'},\n", + " 'embedding': None,\n", + " 'score': 0.300053447242}]}]}" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = {\n", + " \"query\": \"How does Tesla deliver cars?\",\n", + " \"filter\": {\"source_id\": \"test:twtr10k|test:tesla10k\"},\n", + " \"top_k\": 3\n", + "}\n", + "\n", + "response = requests.post(\n", + " f\"{endpoint_url}/query\",\n", + " headers=headers,\n", + " json={\n", + " \"queries\": [query]\n", + " }\n", + ")\n", + "response.raise_for_status()\n", + "\n", + "response.json()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example we use a wild card to filter by prefix. There are three documents matching this filter so three results will be printed.\n", + "\n", + "Gotcha, only prefix filtering is supported for redis TAGS, i.e. \"test*\" is valid, where as \"te\\*t\\*\" is not." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'results': [{'query': 'I want information related to car dealerships.',\n", + " 'results': [{'id': 'tsla',\n", + " 'text': 'Because we do not have independent dealer networks, we are responsible for delivering all of our vehicles to our customers.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:tesla10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/1318605/000095017022000796/tsla-20211231.htm',\n", + " 'created_at': '1640908800',\n", + " 'author': 'Elvis Tusk Jr.',\n", + " 'document_id': 'tsla'},\n", + " 'embedding': None,\n", + " 'score': 0.204279193893},\n", + " {'id': 'twtr',\n", + " 'text': 'Postponements, suspensions or cancellations of major events, such as sporting events and music festivals, may lead to people perceiving the content on Twitter as less relevant or useful or of lower quality, which could negatively affect mDAU growth, or may reduce monetization opportunities in connection with such events.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:twtr10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/1418091/000141809121000031/twtr-20201231.htm',\n", + " 'created_at': '1609372800',\n", + " 'author': 'Elvis Tusk Sr.',\n", + " 'document_id': 'twtr'},\n", + " 'embedding': None,\n", + " 'score': 0.292188997496},\n", + " {'id': 'xom',\n", + " 'text': 'All practical and economically-viable energy sources will need to be pursued to continue meeting global energy demand, recognizing the scale and variety of worldwide energy needs as well as the importance of expanding access to modern energy to promote better standards of living for billions of people.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:xom10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/34088/000003408821000012/xom-20201231.htm',\n", + " 'created_at': '1609372800',\n", + " 'author': 'Vape Jordan',\n", + " 'document_id': 'xom'},\n", + " 'embedding': None,\n", + " 'score': 0.305264299269}]}]}" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = {\n", + " \"query\": \"I want information related to car dealerships.\",\n", + " \"filter\": {\"source_id\": \"test:*\"},\n", + " \"top_k\": 3\n", + "}\n", + "\n", + "response = requests.post(\n", + " f\"{endpoint_url}/query\",\n", + " headers=headers,\n", + " json={\n", + " \"queries\": [query]\n", + " }\n", + ")\n", + "response.raise_for_status()\n", + "\n", + "response.json()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The last example we filter by the \"author\" field. The author field is a TextField, and so we have more options for filtering, \n", + "see [here](https://redis.io/docs/stack/search/reference/query_syntax/) for a complete set of examples.\n", + "\n", + "We can select by a specific author, here we only expect to return a single result." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'results': [{'query': 'I want information related to car dealerships.',\n", + " 'results': [{'id': 'xom',\n", + " 'text': 'All practical and economically-viable energy sources will need to be pursued to continue meeting global energy demand, recognizing the scale and variety of worldwide energy needs as well as the importance of expanding access to modern energy to promote better standards of living for billions of people.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:xom10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/34088/000003408821000012/xom-20201231.htm',\n", + " 'created_at': '1609372800',\n", + " 'author': 'Vape Jordan',\n", + " 'document_id': 'xom'},\n", + " 'embedding': None,\n", + " 'score': 0.305264299269}]}]}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = {\n", + " \"query\": \"I want information related to car dealerships.\",\n", + " \"filter\": {\"source_id\": \"test:*\", \"author\": \"Vape Jordan\"},\n", + " \"top_k\": 3\n", + "}\n", + "\n", + "response = requests.post(\n", + " f\"{endpoint_url}/query\",\n", + " headers=headers,\n", + " json={\n", + " \"queries\": [query]\n", + " }\n", + ")\n", + "response.raise_for_status()\n", + "\n", + "response.json()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we use the negation \"-\" to select all documents, except those published by an author called Elvis" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'results': [{'query': 'I want information related to car dealerships.',\n", + " 'results': [{'id': 'xom',\n", + " 'text': 'All practical and economically-viable energy sources will need to be pursued to continue meeting global energy demand, recognizing the scale and variety of worldwide energy needs as well as the importance of expanding access to modern energy to promote better standards of living for billions of people.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:xom10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/34088/000003408821000012/xom-20201231.htm',\n", + " 'created_at': '1609372800',\n", + " 'author': 'Vape Jordan',\n", + " 'document_id': 'xom'},\n", + " 'embedding': None,\n", + " 'score': 0.305264299269}]}]}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = {\n", + " \"query\": \"I want information related to car dealerships.\",\n", + " \"filter\": {\"source_id\": \"test:*\", \"author\": \"-Elvis\"},\n", + " \"top_k\": 3\n", + "}\n", + "\n", + "response = requests.post(\n", + " f\"{endpoint_url}/query\",\n", + " headers=headers,\n", + " json={\n", + " \"queries\": [query]\n", + " }\n", + ")\n", + "response.raise_for_status()\n", + "\n", + "response.json()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last example we filter two of the authors:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'results': [{'query': 'I want information related to car dealerships.',\n", + " 'results': [{'id': 'tsla',\n", + " 'text': 'Because we do not have independent dealer networks, we are responsible for delivering all of our vehicles to our customers.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:tesla10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/1318605/000095017022000796/tsla-20211231.htm',\n", + " 'created_at': '1640908800',\n", + " 'author': 'Elvis Tusk Jr.',\n", + " 'document_id': 'tsla'},\n", + " 'embedding': None,\n", + " 'score': 0.204279193893},\n", + " {'id': 'xom',\n", + " 'text': 'All practical and economically-viable energy sources will need to be pursued to continue meeting global energy demand, recognizing the scale and variety of worldwide energy needs as well as the importance of expanding access to modern energy to promote better standards of living for billions of people.',\n", + " 'metadata': {'source': 'file',\n", + " 'source_id': 'test:xom10k',\n", + " 'url': 'https://www.sec.gov/Archives/edgar/data/34088/000003408821000012/xom-20201231.htm',\n", + " 'created_at': '1609372800',\n", + " 'author': 'Vape Jordan',\n", + " 'document_id': 'xom'},\n", + " 'embedding': None,\n", + " 'score': 0.305264299269}]}]}" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = {\n", + " \"query\": \"I want information related to car dealerships.\",\n", + " \"filter\": {\"source_id\": \"test:*\", \"author\": \"Elvis*Jr.|Vape\"},\n", + " \"top_k\": 3\n", + "}\n", + "\n", + "response = requests.post(\n", + " f\"{endpoint_url}/query\",\n", + " headers=headers,\n", + " json={\n", + " \"queries\": [query]\n", + " }\n", + ")\n", + "response.raise_for_status()\n", + "\n", + "response.json()" + ] + } + ], + "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.1" + }, + "vscode": { + "interpreter": { + "hash": "1979a773a5778de9a5fa593a629dff0ab3c80c2563810d3e6a8dfb123dc01c7d" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/providers/supabase/.gitignore b/examples/providers/supabase/.gitignore new file mode 100644 index 000000000..773c7c3e0 --- /dev/null +++ b/examples/providers/supabase/.gitignore @@ -0,0 +1,3 @@ +# Supabase +.branches +.temp diff --git a/examples/providers/supabase/config.toml b/examples/providers/supabase/config.toml new file mode 100644 index 000000000..921313039 --- /dev/null +++ b/examples/providers/supabase/config.toml @@ -0,0 +1,72 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the working +# directory name when running `supabase init`. +project_id = "providers" + +[api] +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. public and storage are always included. +schemas = ["public", "storage", "graphql_public"] +# Extra schemas to add to the search_path of every request. public is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[db] +# Port to use for the local database URL. +port = 54322 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[studio] +# Port to use for Supabase Studio. +port = 54323 + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +# Port to use for the email testing server web interface. +port = 54324 +smtp_port = 54325 +pop3_port = 54326 + +[storage] +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[auth] +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://localhost:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://localhost:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one +# week). +jwt_expiry = 3600 +# Allow/disallow new user signups to your project. +enable_signup = true + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +secret = "" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" diff --git a/examples/providers/supabase/migrations/20230414142107_init_pg_vector.sql b/examples/providers/supabase/migrations/20230414142107_init_pg_vector.sql new file mode 100644 index 000000000..4d54797b2 --- /dev/null +++ b/examples/providers/supabase/migrations/20230414142107_init_pg_vector.sql @@ -0,0 +1,70 @@ +create extension vector; + +create table if not exists documents ( + id text primary key default gen_random_uuid()::text, + source text, + source_id text, + content text, + document_id text, + author text, + url text, + created_at timestamptz default now(), + embedding vector(1536) +); + +create index ix_documents_document_id on documents using btree ( document_id ); +create index ix_documents_source on documents using btree ( source ); +create index ix_documents_source_id on documents using btree ( source_id ); +create index ix_documents_author on documents using btree ( author ); +create index ix_documents_created_at on documents using brin ( created_at ); + +alter table documents enable row level security; + +create or replace function match_page_sections(in_embedding vector(1536) + , in_match_count int default 3 + , in_document_id text default '%%' + , in_source_id text default '%%' + , in_source text default '%%' + , in_author text default '%%' + , in_start_date timestamptz default '-infinity' + , in_end_date timestamptz default 'infinity') +returns table (id text + , source text + , source_id text + , document_id text + , url text + , created_at timestamptz + , author text + , content text + , embedding vector(1536) + , similarity float) +language plpgsql +as $$ +#variable_conflict use_variable +begin +return query +select + documents.id, + documents.source, + documents.source_id, + documents.document_id, + documents.url, + documents.created_at, + documents.author, + documents.content, + documents.embedding, + (documents.embedding <#> in_embedding) * -1 as similarity +from documents + +where in_start_date <= documents.created_at and + documents.created_at <= in_end_date and + (documents.source_id like in_source_id or documents.source_id is null) and + (documents.source like in_source or documents.source is null) and + (documents.author like in_author or documents.author is null) and + (documents.document_id like in_document_id or documents.document_id is null) + +order by documents.embedding <#> in_embedding + +limit in_match_count; +end; +$$; \ No newline at end of file diff --git a/examples/providers/supabase/seed.sql b/examples/providers/supabase/seed.sql new file mode 100644 index 000000000..e69de29bb diff --git a/local_server/ai-plugin.json b/local_server/ai-plugin.json new file mode 100644 index 000000000..5911818a8 --- /dev/null +++ b/local_server/ai-plugin.json @@ -0,0 +1,18 @@ +{ + "schema_version": "v1", + "name_for_model": "retrieval", + "name_for_human": "Retrieval Plugin", + "description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.", + "description_for_human": "Search through your documents.", + "auth": { + "type": "none" + }, + "api": { + "type": "openapi", + "url": "http://localhost:3333/.well-known/openapi.yaml" + }, + "logo_url": "http://localhost:3333/.well-known/logo.png", + "contact_email": "hello@contact.com", + "legal_info_url": "hello@legal.com" +} + diff --git a/local_server/logo.png b/local_server/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..af562f798e9ba772e44fb42c21d3b9de398d120d GIT binary patch literal 17015 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 literal 0 HcmV?d00001 diff --git a/models/__pycache__/models.cpython-310.pyc b/models/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d02e66d45638559136d23475a7b4a88f7f2424d2 GIT binary patch literal 2845 zcmaJ@OONA35VqsDlgxNB?_C}O#KWLrIKgFvMhgoUHV8%t$pV2R zXZFso=>wNN?RjsU_^O?ZXR`4o>WaUvPP^)>>d&sn{}?!8JHR`94F4AJgzW!@Rt3^4ZwYNVez&S>91jCKQWJWSzW@52HVlyjon2mcl%Dt!;V#bxj%PcRH z{WveUvS(MBoW`#5)3nM;o~9~H)3RoZg04qt`gD;Mtw(scf$+%$FwYG!rfV|)eRX8rPBIkc(#mT%_T;|m&cIHL1{P}!-EnNJYMnn7hhHcuWZ|d3C z61A}6oR)t_ciG^Kum|jGY-t?aU|Zwx20I!LZ?H=kba^WJww^6Y zUdcyXW-OE0RJl#dV9@@iIaAg`6e^qvo=MKqOe!~9$g5h!BSHNwhGa%$A~H4^N>^>C zX;xLW%&59enu;BowHhhJgcj|R*&}m9a(lH!bK5YqYeOb9BD4MOncCCO+&ftQCgza2 zrS?~ue{;2{o^s zN0I5gv$nWCiW%_m*w7823yic}HNKP9R1Hu*Tk=0~#>!=hRlv*NIb(Ts84uSJyoW&6 z6Qt0^+hnLYmGii$Gr2MCWB7@phT4KE=Hq*03Yzavo~Z1S=jd~0qC*F|P6u}q`ZbqV z7qeR6fH(9rjh*!jsQUedc^6(9%fgIIL8w2rFX8QCTR(-X!rVEHxuHS?A0}QPxE!Su>n(fWz72T!FhL}eCIJelItRg0&^~q?I zJEIfQKtI=mwy>S9Z9m@>VT|#rJqVF0Xr?#9rh>PNaGmcvJa?+ss$!>lE$&pW#ai`} z5e`m^y`>8J>ZZq5GVonqNG_&AA9t;3BwSjlRM^N&$P{A9mCq}tuj27KH=C3~??l3= zb+8q_j|qN4W|NM51jh+RLxR{zU}U1y6!!S5{tamJDhRignq> zK13e5(QI#S;(d4_;S(Jtb?U>FplO-v>(nHxCp+S@hnw!SE%Aa4e ztdjXm3^1cyc|C{DYvI-=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] +test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (<0.22)"] + +[[package]] +name = "arrow" +version = "1.2.3" +description = "Better dates & times for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "arrow-1.2.3-py3-none-any.whl", hash = "sha256:5a49ab92e3b7b71d96cd6bfcc4df14efefc9dfa96ea19045815914a6ab6b1fe2"}, + {file = "arrow-1.2.3.tar.gz", hash = "sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1"}, +] + +[package.dependencies] +python-dateutil = ">=2.7.0" + +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + +[[package]] +name = "authlib" +version = "1.2.1" +description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." +optional = false +python-versions = "*" +files = [ + {file = "Authlib-1.2.1-py2.py3-none-any.whl", hash = "sha256:c88984ea00149a90e3537c964327da930779afa4564e354edfd98410bea01911"}, + {file = "Authlib-1.2.1.tar.gz", hash = "sha256:421f7c6b468d907ca2d9afede256f068f87e34d23dd221c07d13d4c234726afb"}, +] + +[package.dependencies] +cryptography = ">=3.2" + +[[package]] +name = "azure-common" +version = "1.1.28" +description = "Microsoft Azure Client Library for Python (Common)" +optional = false +python-versions = "*" +files = [ + {file = "azure-common-1.1.28.zip", hash = "sha256:4ac0cd3214e36b6a1b6a442686722a5d8cc449603aa833f3f0f40bda836704a3"}, + {file = "azure_common-1.1.28-py2.py3-none-any.whl", hash = "sha256:5c12d3dcf4ec20599ca6b0d3e09e86e146353d443e7fcc050c9a19c1f9df20ad"}, +] + +[[package]] +name = "azure-core" +version = "1.29.2" +description = "Microsoft Azure Core Library for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "azure-core-1.29.2.zip", hash = "sha256:beb0fe88d1043d8457318e8fb841d9caa648211092eda213c16b376401f3710d"}, + {file = "azure_core-1.29.2-py3-none-any.whl", hash = "sha256:8e6602f322dc1070caf7e17754beb53b69ffa09df0f4786009a3107e9a00c793"}, +] + +[package.dependencies] +requests = ">=2.18.4" +six = ">=1.11.0" +typing-extensions = ">=4.6.0" + +[package.extras] +aio = ["aiohttp (>=3.0)"] + +[[package]] +name = "azure-identity" +version = "1.14.0" +description = "Microsoft Azure Identity Library for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "azure-identity-1.14.0.zip", hash = "sha256:72441799f8c5c89bfe21026965e266672a7c5d050c2c65119ef899dd5362e2b1"}, + {file = "azure_identity-1.14.0-py3-none-any.whl", hash = "sha256:edabf0e010eb85760e1dd19424d5e8f97ba2c9caff73a16e7b30ccbdbcce369b"}, +] + +[package.dependencies] +azure-core = ">=1.11.0,<2.0.0" +cryptography = ">=2.5" +msal = ">=1.20.0,<2.0.0" +msal-extensions = ">=0.3.0,<2.0.0" + +[[package]] +name = "azure-search-documents" +version = "11.4.0a20230509004" +description = "Microsoft Azure Cognitive Search Client Library for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "azure-search-documents-11.4.0a20230509004.zip", hash = "sha256:6cca144573161a10aa0fcd13927264453e79c63be6a53cf2ec241c9c8c22f6b5"}, + {file = "azure_search_documents-11.4.0a20230509004-py3-none-any.whl", hash = "sha256:6215e9a4f9e935ff3eac1b7d5519c6c0789b4497eb11242d376911aaefbb0359"}, +] + +[package.dependencies] +azure-common = ">=1.1,<2.0" +azure-core = ">=1.24.0,<2.0.0" +isodate = ">=0.6.0" + +[package.source] +type = "legacy" +url = "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple" +reference = "azure-sdk-dev" + +[[package]] +name = "backoff" +version = "2.2.1" +description = "Function decoration for backoff and retry" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, +] + +[[package]] +name = "bleach" +version = "6.0.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.7" +files = [ + {file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"}, + {file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"}, +] + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.2)"] + +[[package]] +name = "blobfile" +version = "2.0.2" +description = "Read GCS, ABS and local paths with the same interface, clone of tensorflow.io.gfile" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "blobfile-2.0.2-py3-none-any.whl", hash = "sha256:c48afb61d14d6f94b0c109aa35475bc8d586e5eecde9a25dc2c9c52e7dd4feaf"}, +] + +[package.dependencies] +filelock = ">=3.0,<4.0" +lxml = ">=4.9,<5.0" +pycryptodomex = ">=3.8,<4.0" +urllib3 = ">=1.25.3,<3" + +[[package]] +name = "certifi" +version = "2023.7.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, +] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.2.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, + {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, +] + +[[package]] +name = "chromadb" +version = "0.3.26" +description = "Chroma." +optional = false +python-versions = ">=3.7" +files = [ + {file = "chromadb-0.3.26-py3-none-any.whl", hash = "sha256:45a7848ee3ed8b694ca5789e5fd723406b76a13fa46f9a9a769f93317f29894c"}, + {file = "chromadb-0.3.26.tar.gz", hash = "sha256:a9b596d507f081993f2e32a7dcacabbbec2f6aebc2b6defe524442b07e265296"}, +] + +[package.dependencies] +clickhouse-connect = ">=0.5.7" +duckdb = ">=0.7.1" +fastapi = ">=0.85.1" +hnswlib = ">=0.7" +numpy = ">=1.21.6" +onnxruntime = ">=1.14.1" +overrides = ">=7.3.1" +pandas = ">=1.3" +posthog = ">=2.4.0" +pulsar-client = ">=3.1.0" +pydantic = ">=1.9" +requests = ">=2.28" +tokenizers = ">=0.13.2" +tqdm = ">=4.65.0" +typing-extensions = ">=4.5.0" +uvicorn = {version = ">=0.18.3", extras = ["standard"]} + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click-log" +version = "0.4.0" +description = "Logging integration for Click" +optional = false +python-versions = "*" +files = [ + {file = "click-log-0.4.0.tar.gz", hash = "sha256:3970f8570ac54491237bcdb3d8ab5e3eef6c057df29f8c3d1151a51a9c23b975"}, + {file = "click_log-0.4.0-py2.py3-none-any.whl", hash = "sha256:a43e394b528d52112af599f2fc9e4b7cf3c15f94e53581f74fa6867e68c91756"}, +] + +[package.dependencies] +click = "*" + +[[package]] +name = "clickhouse-connect" +version = "0.6.9" +description = "ClickHouse Database Core Driver for Python, Pandas, and Superset" +optional = false +python-versions = "~=3.7" +files = [ + {file = "clickhouse-connect-0.6.9.tar.gz", hash = "sha256:ba735bcb73c4743788e7c8bfeb865edd887da28a253bd189c449df20d9abff64"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74fb1bc9eea037db1361d75adb6482ce6d8c22e4a47a37735edd8e3862d931f7"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb5e4a489b5960fc4bc48fdda052b3a446a736ee4be74105ae7663307da8a063"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e954bfe759fd437595732a15a40356e9e29035a83f485a23601f863aab2f7c6f"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2f4ada702a933f2ffc38e77bf948f11d745f3467191d6b6fc2190683d02bb8"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d06a56e2be745adb692fbf1eedd9fb6d5dbb46ce325c1d9e57b53ba99eee95"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5dcbd145ad907e9bc7dbbc5e80440888201de8f1622f755032595c8b8302e4ef"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f155d1f214c81c5d8e72cbe325dfec72340c082156108db06c862ddd76771d7e"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0b47ec963b9d9cf1674490385183dc988d6e4d33287bb9d81e23373012232223"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-win32.whl", hash = "sha256:59dc14e47fa287578495835e4c5efdff90e40430b5b27a3c1453bb83d65e17cb"}, + {file = "clickhouse_connect-0.6.9-cp310-cp310-win_amd64.whl", hash = "sha256:bcabfaa3fbef4ea9ba723d16e9f50e5e02a3c871b3afc8106b6a04a53a7b19d7"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93025ec43ffc25ae3e5111c0da65f8227dc6ae68834beeda3b0256c22baedd9f"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac72323af794b4c79a804f4f311cfe4ae28426f92ac1b7f390aabbab6a93a4bd"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d8c1e71b34e870d8cd4805c3be86678e19a63931a718f3bf657b48da82c74df"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c286a6814facf3fa5bf492863e99b300154b33c3ecedf7799070ef9b8cd12474"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9924d53302f3333bcc40b9f5238bea4c29c107a6a82e22dc5ba24ce7c1cdb75"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:adf29b7319e5cdb9b6cb8ec3d4e85056e588ac51265b92ffaf6c69481283e643"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6fc2d4e428af2be8c9db23b37f4493848696417376f0eaba23b0e8f053f6a0d4"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b3793d26cabd88bad6f4a3fe9f93974e480cc785f137158be8b58d700baaeb4f"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-win32.whl", hash = "sha256:1fa2fddd00d019b4593b194a303339268699808c5ebeab2d331b2ee0d29eabc0"}, + {file = "clickhouse_connect-0.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:536df34ecb49ddd7c61ebd6b900a7d06b3a246fbe30441cb68c568ea42e292d3"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d61337ca4c48b78a959627e9c0de58b86a8399510de184bd6d4c27b8b7e93c17"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69449ee694ed9aa4ee5f290c13ce5038efe394ff99b43eeee8e8190f3e4aa909"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b97ee1de55fea90f12e1f04ea6521dd827f2ed25361cfb99374cb0649222a8f0"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:adc42d8970b322bf78053a62e6c555fd8e03b29aecffe21521efaf5bad4e2ba4"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:064a27bd8d92f413ddcf20926a6c868a0482f7e757f9d412c0778b875d20c536"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a4aaf279efc5e8e13c6b4ac7ce41a3700f786dd34a58d3686ddf29660364dc62"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:022e0438728cc323d1817ade5105e4458acf71be822dffee130934140524fcbd"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-win32.whl", hash = "sha256:e7a9c511f680e0f40b8765e7fbb8bde6b101cbf0a5b180f6ccc18ad59c9776ea"}, + {file = "clickhouse_connect-0.6.9-cp37-cp37m-win_amd64.whl", hash = "sha256:c2bd8fc5767fd883d5d1ca2e35e3034e590994ea64f76b11a3814ab20862a0b0"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:159cba55d55ea85cea310a8781144559deade5c8cee6b13bc720253e6a6e4a5c"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f4a34a7e3d16c0e4c34a11b7d8cbd633f22ee48e1a193f1977f64fe470ad9c79"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:026b9363553a6bd22f5c9f4b65cacd3c3fc0b50d5d0159c47bb34f63dc87ccff"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaec4e9dc5110bf6f17a0abbb61e286293400d2c3450e29040fd100dc075dc89"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0224509fd36637ccf1add66f4ec12d464e2e80e4a5521e846f4d7602b6664a0c"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aa5b9b5699ae385d4f7c1f493e1029d7803b47c74ecb2502f01fb79135253d2"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1b0418b347f4e7a27e692f6947b9788759b23ee4f4aabccbb376b5241190f8a7"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:80778a118f5b2c52daf64c051fdbc5df23a8c37e9e385205e4942fdd60925d25"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-win32.whl", hash = "sha256:841838e793cd4283d3a245e278b136ea5681e636dcdc816c27c4ff77e4bb2077"}, + {file = "clickhouse_connect-0.6.9-cp38-cp38-win_amd64.whl", hash = "sha256:63de88cf244adda961742c1e05e051340de09714b38cc33d757138af6033b364"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47216788f28fa8d1c225acdd366f5eab53c00b131ca246c7f004d94b1aff7cef"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8b6669ba538b6fe18cbe01f4451c4e5d5674471cd55aec7af3d6f1a8e064b8f"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43de9421a8f91e82efec5f9bffe366fb341e2fb7c7dce89e303061ba7065baa3"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62b184813807112a8ef2853df93b6c07899bdf04f188e547f92c54fc2e056be3"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5c869d6761f38bfb940fa0992078bd7d8ece1c1c47a330ab3e8390ca8b2ba980"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b83f62002ae8a19102f05868639217fe3dddabf4c099dc0ddf1586901f1501fb"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:442f9119a223c4f97608d3e4f38debc9c62873e0e9dc948cb1b21691be35af55"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cef80d7596887eff39256e29a31c23297a1a65aac735b3e0e323c702dd95d2ee"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-win32.whl", hash = "sha256:f9cdccf6fa12349e4c25d099bed1d80274104cc4e4a8110f6692e553f4491b99"}, + {file = "clickhouse_connect-0.6.9-cp39-cp39-win_amd64.whl", hash = "sha256:067b5b104e0ac1e16255313766cd97cccd06285ab36f7a2bea7960bd643f5c13"}, + {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e08de57aeb1272897208f91873511090d3f904fede4e509f9b2a0ff00db4d49"}, + {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5318b4ac3fbf91ed3ab766bfa55b5ce72ba520181ad6f61fbf37ed63150033f4"}, + {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df27dfab1565dce2dad8d6ff41a9bc35fb52ed56fba857f26faffac05ffe201"}, + {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71319fde3214e2382bc7ec402268b9b8c320a2eb86ea764e79a29f7562de06fd"}, + {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:7e0910ac23e7c1ba9af00818f52cdfc812210b4ab10c2be54f1f6456e144e0a7"}, + {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8566b0b57537b570bbef6736d461108c2354e40bd1b7166f9f51cc2e0d8124cb"}, + {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c7a0f9c9dcb3bb482043a2b0e3ceb371b17d7ad320317529c2834960649fd20"}, + {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70ae9442b369fa6365018ee92cda1fa26eade3b87640c744b8e3d327872cd8ae"}, + {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c018fcf03428f940dfa52eea7ff443dea9eee20c2e161486d0a6d2509693904"}, + {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:adb7d4a449af756ad9c5b2074ce7844ef34981827cce7510151a8a01493e68f3"}, + {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:66a1d90bcd837734efbe3060f17b98a071f773cac50183efc9a6d2dc40bdbce6"}, + {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41fbc4a75f7098d38246528af34a17b9b7411fb63914787141c82d178bc189be"}, + {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b6da9732b26cd98b8ed672bc7684ccf7a589f8d7f56faa7439f8d78b5f4c32"}, + {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c1954ba9735bf4af6737adc9da68179b6c49b698e288e839705c5c0a260ce85"}, + {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fa6b01af8c82b860fb4799651dc10a79645b88c8ee103bb14c6e8cdd8b00d8bd"}, +] + +[package.dependencies] +certifi = "*" +lz4 = "*" +pytz = "*" +urllib3 = ">=1.26" +zstandard = "*" + +[package.extras] +arrow = ["pyarrow"] +numpy = ["numpy"] +orjson = ["orjson"] +pandas = ["pandas"] +sqlalchemy = ["sqlalchemy (>1.3.21,<2.0)"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coloredlogs" +version = "15.0.1" +description = "Colored terminal output for Python's logging module" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] + +[package.dependencies] +humanfriendly = ">=9.1" + +[package.extras] +cron = ["capturer (>=2.4)"] + +[[package]] +name = "coverage" +version = "7.3.0" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, + {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, + {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, + {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, + {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, + {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, + {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, + {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, + {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, + {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, + {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, + {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, + {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, + {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "cryptography" +version = "41.0.3" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507"}, + {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116"}, + {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c"}, + {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae"}, + {file = "cryptography-41.0.3-cp37-abi3-win32.whl", hash = "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306"}, + {file = "cryptography-41.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4"}, + {file = "cryptography-41.0.3.tar.gz", hash = "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "dataclasses-json" +version = "0.5.9" +description = "Easily serialize dataclasses to and from JSON" +optional = false +python-versions = ">=3.6" +files = [ + {file = "dataclasses-json-0.5.9.tar.gz", hash = "sha256:e9ac87b73edc0141aafbce02b44e93553c3123ad574958f0fe52a534b6707e8e"}, + {file = "dataclasses_json-0.5.9-py3-none-any.whl", hash = "sha256:1280542631df1c375b7bc92e5b86d39e06c44760d7e3571a537b3b8acabf2f0c"}, +] + +[package.dependencies] +marshmallow = ">=3.3.0,<4.0.0" +marshmallow-enum = ">=1.5.1,<2.0.0" +typing-inspect = ">=0.4.0" + +[package.extras] +dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=7.2.0)", "setuptools", "simplejson", "twine", "types-dataclasses", "wheel"] + +[[package]] +name = "deprecation" +version = "2.1.0" +description = "A library to handle automated deprecations" +optional = false +python-versions = "*" +files = [ + {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, + {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, +] + +[package.dependencies] +packaging = "*" + +[[package]] +name = "dnspython" +version = "2.4.2" +description = "DNS toolkit" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "dnspython-2.4.2-py3-none-any.whl", hash = "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8"}, + {file = "dnspython-2.4.2.tar.gz", hash = "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"}, +] + +[package.extras] +dnssec = ["cryptography (>=2.6,<42.0)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"] +doq = ["aioquic (>=0.9.20)"] +idna = ["idna (>=2.1,<4.0)"] +trio = ["trio (>=0.14,<0.23)"] +wmi = ["wmi (>=1.5.1,<2.0.0)"] + +[[package]] +name = "docutils" +version = "0.20.1" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, +] + +[[package]] +name = "docx2txt" +version = "0.8" +description = "A pure python-based utility to extract text and images from docx files." +optional = false +python-versions = "*" +files = [ + {file = "docx2txt-0.8.tar.gz", hash = "sha256:2c06d98d7cfe2d3947e5760a57d924e3ff07745b379c8737723922e7009236e5"}, +] + +[[package]] +name = "dotty-dict" +version = "1.3.1" +description = "Dictionary wrapper for quick access to deeply nested keys." +optional = false +python-versions = ">=3.5,<4.0" +files = [ + {file = "dotty_dict-1.3.1-py3-none-any.whl", hash = "sha256:5022d234d9922f13aa711b4950372a06a6d64cb6d6db9ba43d0ba133ebfce31f"}, + {file = "dotty_dict-1.3.1.tar.gz", hash = "sha256:4b016e03b8ae265539757a53eba24b9bfda506fb94fbce0bee843c6f05541a15"}, +] + +[[package]] +name = "duckdb" +version = "0.8.1" +description = "DuckDB embedded database" +optional = false +python-versions = "*" +files = [ + {file = "duckdb-0.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:14781d21580ee72aba1f5dcae7734674c9b6c078dd60470a08b2b420d15b996d"}, + {file = "duckdb-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f13bf7ab0e56ddd2014ef762ae4ee5ea4df5a69545ce1191b8d7df8118ba3167"}, + {file = "duckdb-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4032042d8363e55365bbca3faafc6dc336ed2aad088f10ae1a534ebc5bcc181"}, + {file = "duckdb-0.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a71bd8f0b0ca77c27fa89b99349ef22599ffefe1e7684ae2e1aa2904a08684"}, + {file = "duckdb-0.8.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24568d6e48f3dbbf4a933109e323507a46b9399ed24c5d4388c4987ddc694fd0"}, + {file = "duckdb-0.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297226c0dadaa07f7c5ae7cbdb9adba9567db7b16693dbd1b406b739ce0d7924"}, + {file = "duckdb-0.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5792cf777ece2c0591194006b4d3e531f720186102492872cb32ddb9363919cf"}, + {file = "duckdb-0.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:12803f9f41582b68921d6b21f95ba7a51e1d8f36832b7d8006186f58c3d1b344"}, + {file = "duckdb-0.8.1-cp310-cp310-win32.whl", hash = "sha256:d0953d5a2355ddc49095e7aef1392b7f59c5be5cec8cdc98b9d9dc1f01e7ce2b"}, + {file = "duckdb-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:6e6583c98a7d6637e83bcadfbd86e1f183917ea539f23b6b41178f32f813a5eb"}, + {file = "duckdb-0.8.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fad7ed0d4415f633d955ac24717fa13a500012b600751d4edb050b75fb940c25"}, + {file = "duckdb-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81ae602f34d38d9c48dd60f94b89f28df3ef346830978441b83c5b4eae131d08"}, + {file = "duckdb-0.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d75cfe563aaa058d3b4ccaaa371c6271e00e3070df5de72361fd161b2fe6780"}, + {file = "duckdb-0.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dbb55e7a3336f2462e5e916fc128c47fe1c03b6208d6bd413ac11ed95132aa0"}, + {file = "duckdb-0.8.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6df53efd63b6fdf04657385a791a4e3c4fb94bfd5db181c4843e2c46b04fef5"}, + {file = "duckdb-0.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b188b80b70d1159b17c9baaf541c1799c1ce8b2af4add179a9eed8e2616be96"}, + {file = "duckdb-0.8.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5ad481ee353f31250b45d64b4a104e53b21415577943aa8f84d0af266dc9af85"}, + {file = "duckdb-0.8.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1d1b1729993611b1892509d21c21628917625cdbe824a61ce891baadf684b32"}, + {file = "duckdb-0.8.1-cp311-cp311-win32.whl", hash = "sha256:2d8f9cc301e8455a4f89aa1088b8a2d628f0c1f158d4cf9bc78971ed88d82eea"}, + {file = "duckdb-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:07457a43605223f62d93d2a5a66b3f97731f79bbbe81fdd5b79954306122f612"}, + {file = "duckdb-0.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d2c8062c3e978dbcd80d712ca3e307de8a06bd4f343aa457d7dd7294692a3842"}, + {file = "duckdb-0.8.1-cp36-cp36m-win32.whl", hash = "sha256:fad486c65ae944eae2de0d590a0a4fb91a9893df98411d66cab03359f9cba39b"}, + {file = "duckdb-0.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:86fa4506622c52d2df93089c8e7075f1c4d0ba56f4bf27faebde8725355edf32"}, + {file = "duckdb-0.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:60e07a62782f88420046e30cc0e3de842d0901c4fd5b8e4d28b73826ec0c3f5e"}, + {file = "duckdb-0.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f18563675977f8cbf03748efee0165b4c8ef64e0cbe48366f78e2914d82138bb"}, + {file = "duckdb-0.8.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16e179443832bea8439ae4dff93cf1e42c545144ead7a4ef5f473e373eea925a"}, + {file = "duckdb-0.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a413d5267cb41a1afe69d30dd6d4842c588256a6fed7554c7e07dad251ede095"}, + {file = "duckdb-0.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3784680df59eadd683b0a4c2375d451a64470ca54bd171c01e36951962b1d332"}, + {file = "duckdb-0.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:67a1725c2b01f9b53571ecf3f92959b652f60156c1c48fb35798302e39b3c1a2"}, + {file = "duckdb-0.8.1-cp37-cp37m-win32.whl", hash = "sha256:197d37e2588c5ad063e79819054eedb7550d43bf1a557d03ba8f8f67f71acc42"}, + {file = "duckdb-0.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3843feb79edf100800f5037c32d5d5a5474fb94b32ace66c707b96605e7c16b2"}, + {file = "duckdb-0.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:624c889b0f2d656794757b3cc4fc58030d5e285f5ad2ef9fba1ea34a01dab7fb"}, + {file = "duckdb-0.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fcbe3742d77eb5add2d617d487266d825e663270ef90253366137a47eaab9448"}, + {file = "duckdb-0.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47516c9299d09e9dbba097b9fb339b389313c4941da5c54109df01df0f05e78c"}, + {file = "duckdb-0.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf1ba718b7522d34399446ebd5d4b9fcac0b56b6ac07bfebf618fd190ec37c1d"}, + {file = "duckdb-0.8.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e36e35d38a9ae798fe8cf6a839e81494d5b634af89f4ec9483f4d0a313fc6bdb"}, + {file = "duckdb-0.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23493313f88ce6e708a512daacad13e83e6d1ea0be204b175df1348f7fc78671"}, + {file = "duckdb-0.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1fb9bf0b6f63616c8a4b9a6a32789045e98c108df100e6bac783dc1e36073737"}, + {file = "duckdb-0.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:12fc13ecd5eddd28b203b9e3999040d3a7374a8f4b833b04bd26b8c5685c2635"}, + {file = "duckdb-0.8.1-cp38-cp38-win32.whl", hash = "sha256:a12bf4b18306c9cb2c9ba50520317e6cf2de861f121d6f0678505fa83468c627"}, + {file = "duckdb-0.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e4e809358b9559c00caac4233e0e2014f3f55cd753a31c4bcbbd1b55ad0d35e4"}, + {file = "duckdb-0.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7acedfc00d97fbdb8c3d120418c41ef3cb86ef59367f3a9a30dff24470d38680"}, + {file = "duckdb-0.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:99bfe264059cdc1e318769103f656f98e819cd4e231cd76c1d1a0327f3e5cef8"}, + {file = "duckdb-0.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:538b225f361066231bc6cd66c04a5561de3eea56115a5dd773e99e5d47eb1b89"}, + {file = "duckdb-0.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae0be3f71a18cd8492d05d0fc1bc67d01d5a9457b04822d025b0fc8ee6efe32e"}, + {file = "duckdb-0.8.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd82ba63b58672e46c8ec60bc9946aa4dd7b77f21c1ba09633d8847ad9eb0d7b"}, + {file = "duckdb-0.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:780a34559aaec8354e83aa4b7b31b3555f1b2cf75728bf5ce11b89a950f5cdd9"}, + {file = "duckdb-0.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:01f0d4e9f7103523672bda8d3f77f440b3e0155dd3b2f24997bc0c77f8deb460"}, + {file = "duckdb-0.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31f692decb98c2d57891da27180201d9e93bb470a3051fcf413e8da65bca37a5"}, + {file = "duckdb-0.8.1-cp39-cp39-win32.whl", hash = "sha256:e7fe93449cd309bbc67d1bf6f6392a6118e94a9a4479ab8a80518742e855370a"}, + {file = "duckdb-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:81d670bc6807672f038332d9bf587037aabdd741b0810de191984325ed307abd"}, + {file = "duckdb-0.8.1.tar.gz", hash = "sha256:a54d37f4abc2afc4f92314aaa56ecf215a411f40af4bffe1e86bd25e62aceee9"}, +] + +[[package]] +name = "elastic-transport" +version = "8.4.0" +description = "Transport classes and utilities shared among Python Elastic client libraries" +optional = false +python-versions = ">=3.6" +files = [ + {file = "elastic-transport-8.4.0.tar.gz", hash = "sha256:b9ad708ceb7fcdbc6b30a96f886609a109f042c0b9d9f2e44403b3133ba7ff10"}, + {file = "elastic_transport-8.4.0-py3-none-any.whl", hash = "sha256:19db271ab79c9f70f8c43f8f5b5111408781a6176b54ab2e54d713b6d9ceb815"}, +] + +[package.dependencies] +certifi = "*" +urllib3 = ">=1.26.2,<2" + +[package.extras] +develop = ["aiohttp", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "pytest-mock", "requests", "trustme"] + +[[package]] +name = "elasticsearch" +version = "8.8.2" +description = "Python client for Elasticsearch" +optional = false +python-versions = ">=3.6, <4" +files = [ + {file = "elasticsearch-8.8.2-py3-none-any.whl", hash = "sha256:bffd6ce4faaacf90e6f617241773b3da8fb94e2e83554f5508e2fab92ca79643"}, + {file = "elasticsearch-8.8.2.tar.gz", hash = "sha256:bed8cf8fcc6c3be7c254b579de4c29afab021f373c832246f912d37aef3c6bd5"}, +] + +[package.dependencies] +elastic-transport = ">=8,<9" + +[package.extras] +async = ["aiohttp (>=3,<4)"] +requests = ["requests (>=2.4.0,<3.0.0)"] + +[[package]] +name = "environs" +version = "9.5.0" +description = "simplified environment variable parsing" +optional = false +python-versions = ">=3.6" +files = [ + {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, + {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, +] + +[package.dependencies] +marshmallow = ">=3.0.0" +python-dotenv = "*" + +[package.extras] +dev = ["dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "pytest", "tox"] +django = ["dj-database-url", "dj-email-url", "django-cache-url"] +lint = ["flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] +tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"] + +[[package]] +name = "exceptiongroup" +version = "1.1.3" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fastapi" +version = "0.92.0" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.7" +files = [ + {file = "fastapi-0.92.0-py3-none-any.whl", hash = "sha256:ae7b97c778e2f2ec3fb3cb4fb14162129411d99907fb71920f6d69a524340ebf"}, + {file = "fastapi-0.92.0.tar.gz", hash = "sha256:023a0f5bd2c8b2609014d3bba1e14a1d7df96c6abea0a73070621c9862b9a4de"}, +] + +[package.dependencies] +pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" +starlette = ">=0.25.0,<0.26.0" + +[package.extras] +all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer[all] (>=0.6.1,<0.8.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.10.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.6.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] + +[[package]] +name = "filelock" +version = "3.12.2" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.7" +files = [ + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, +] + +[package.extras] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "flatbuffers" +version = "23.5.26" +description = "The FlatBuffers serialization format for Python" +optional = false +python-versions = "*" +files = [ + {file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1"}, + {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"}, +] + +[[package]] +name = "frozenlist" +version = "1.4.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab"}, + {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559"}, + {file = "frozenlist-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62"}, + {file = "frozenlist-1.4.0-cp310-cp310-win32.whl", hash = "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0"}, + {file = "frozenlist-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956"}, + {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95"}, + {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3"}, + {file = "frozenlist-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb"}, + {file = "frozenlist-1.4.0-cp311-cp311-win32.whl", hash = "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431"}, + {file = "frozenlist-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1"}, + {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3"}, + {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503"}, + {file = "frozenlist-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8"}, + {file = "frozenlist-1.4.0-cp38-cp38-win32.whl", hash = "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc"}, + {file = "frozenlist-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7"}, + {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf"}, + {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963"}, + {file = "frozenlist-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3"}, + {file = "frozenlist-1.4.0-cp39-cp39-win32.whl", hash = "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f"}, + {file = "frozenlist-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167"}, + {file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"}, +] + +[[package]] +name = "gitdb" +version = "4.0.10" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, + {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.32" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.32-py3-none-any.whl", hash = "sha256:e3d59b1c2c6ebb9dfa7a184daf3b6dd4914237e7488a1730a6d8f6f5d0b4187f"}, + {file = "GitPython-3.1.32.tar.gz", hash = "sha256:8d9b8cb1e80b9735e8717c9362079d3ce4c6e5ddeebedd0361b228c3a67a62f6"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[[package]] +name = "gotrue" +version = "1.0.2" +description = "Python Client Library for GoTrue" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "gotrue-1.0.2-py3-none-any.whl", hash = "sha256:5377e7fd316b77df7be9e0c3c017d338bed2ba2e95a99fb44374b523d167ec65"}, + {file = "gotrue-1.0.2.tar.gz", hash = "sha256:9ad9b2536ca68676cf37dc663b64f259956826075e80a9cb3f5a3ba150355811"}, +] + +[package.dependencies] +httpx = ">=0.23,<0.25" +pydantic = ">=1.10.0,<2.0.0" + +[[package]] +name = "greenlet" +version = "2.0.2" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +files = [ + {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, + {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, + {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, + {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, + {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, + {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, + {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, + {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, + {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, + {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, + {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, + {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, + {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, + {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, + {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, + {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, + {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, + {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, + {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, + {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, + {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, + {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, +] + +[package.extras] +docs = ["Sphinx", "docutils (<0.18)"] +test = ["objgraph", "psutil"] + +[[package]] +name = "grpcio" +version = "1.56.0" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.7" +files = [ + {file = "grpcio-1.56.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:fb34ace11419f1ae321c36ccaa18d81cd3f20728cd191250be42949d6845bb2d"}, + {file = "grpcio-1.56.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:008767c0aed4899e657b50f2e0beacbabccab51359eba547f860e7c55f2be6ba"}, + {file = "grpcio-1.56.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:17f47aeb9be0da5337f9ff33ebb8795899021e6c0741ee68bd69774a7804ca86"}, + {file = "grpcio-1.56.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43c50d810cc26349b093bf2cfe86756ab3e9aba3e7e681d360930c1268e1399a"}, + {file = "grpcio-1.56.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:187b8f71bad7d41eea15e0c9812aaa2b87adfb343895fffb704fb040ca731863"}, + {file = "grpcio-1.56.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:881575f240eb5db72ddca4dc5602898c29bc082e0d94599bf20588fb7d1ee6a0"}, + {file = "grpcio-1.56.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c243b158dd7585021d16c50498c4b2ec0a64a6119967440c5ff2d8c89e72330e"}, + {file = "grpcio-1.56.0-cp310-cp310-win32.whl", hash = "sha256:8b3b2c7b5feef90bc9a5fa1c7f97637e55ec3e76460c6d16c3013952ee479cd9"}, + {file = "grpcio-1.56.0-cp310-cp310-win_amd64.whl", hash = "sha256:03a80451530fd3b8b155e0c4480434f6be669daf7ecba56f73ef98f94222ee01"}, + {file = "grpcio-1.56.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:64bd3abcf9fb4a9fa4ede8d0d34686314a7075f62a1502217b227991d9ca4245"}, + {file = "grpcio-1.56.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:fdc3a895791af4addbb826808d4c9c35917c59bb5c430d729f44224e51c92d61"}, + {file = "grpcio-1.56.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:4f84a6fd4482e5fe73b297d4874b62a535bc75dc6aec8e9fe0dc88106cd40397"}, + {file = "grpcio-1.56.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14e70b4dda3183abea94c72d41d5930c333b21f8561c1904a372d80370592ef3"}, + {file = "grpcio-1.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b5ce42a5ebe3e04796246ba50357f1813c44a6efe17a37f8dc7a5c470377312"}, + {file = "grpcio-1.56.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8219f17baf069fe8e42bd8ca0b312b875595e43a70cabf397be4fda488e2f27d"}, + {file = "grpcio-1.56.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:defdd14b518e6e468466f799aaa69db0355bca8d3a5ea75fb912d28ba6f8af31"}, + {file = "grpcio-1.56.0-cp311-cp311-win32.whl", hash = "sha256:50f4daa698835accbbcc60e61e0bc29636c0156ddcafb3891c987e533a0031ba"}, + {file = "grpcio-1.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:59c4e606993a47146fbeaf304b9e78c447f5b9ee5641cae013028c4cca784617"}, + {file = "grpcio-1.56.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:b1f4b6f25a87d80b28dd6d02e87d63fe1577fe6d04a60a17454e3f8077a38279"}, + {file = "grpcio-1.56.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:c2148170e01d464d41011a878088444c13413264418b557f0bdcd1bf1b674a0e"}, + {file = "grpcio-1.56.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:0409de787ebbf08c9d2bca2bcc7762c1efe72eada164af78b50567a8dfc7253c"}, + {file = "grpcio-1.56.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66f0369d27f4c105cd21059d635860bb2ea81bd593061c45fb64875103f40e4a"}, + {file = "grpcio-1.56.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38fdf5bd0a1c754ce6bf9311a3c2c7ebe56e88b8763593316b69e0e9a56af1de"}, + {file = "grpcio-1.56.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:79d4c5911d12a7aa671e5eb40cbb50a830396525014d2d6f254ea2ba180ce637"}, + {file = "grpcio-1.56.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5d2fc471668a7222e213f86ef76933b18cdda6a51ea1322034478df8c6519959"}, + {file = "grpcio-1.56.0-cp37-cp37m-win_amd64.whl", hash = "sha256:991224fd485e088d3cb5e34366053691a4848a6b7112b8f5625a411305c26691"}, + {file = "grpcio-1.56.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:c6f36621aabecbaff3e70c4d1d924c76c8e6a7ffec60c331893640a4af0a8037"}, + {file = "grpcio-1.56.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:1eadd6de258901929223f422ffed7f8b310c0323324caf59227f9899ea1b1674"}, + {file = "grpcio-1.56.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:72836b5a1d4f508ffbcfe35033d027859cc737972f9dddbe33fb75d687421e2e"}, + {file = "grpcio-1.56.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f92a99ab0c7772fb6859bf2e4f44ad30088d18f7c67b83205297bfb229e0d2cf"}, + {file = "grpcio-1.56.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa08affbf672d051cd3da62303901aeb7042a2c188c03b2c2a2d346fc5e81c14"}, + {file = "grpcio-1.56.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2db108b4c8e29c145e95b0226973a66d73ae3e3e7fae00329294af4e27f1c42"}, + {file = "grpcio-1.56.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8674fdbd28266d8efbcddacf4ec3643f76fe6376f73283fd63a8374c14b0ef7c"}, + {file = "grpcio-1.56.0-cp38-cp38-win32.whl", hash = "sha256:bd55f743e654fb050c665968d7ec2c33f03578a4bbb163cfce38024775ff54cc"}, + {file = "grpcio-1.56.0-cp38-cp38-win_amd64.whl", hash = "sha256:c63bc5ac6c7e646c296fed9139097ae0f0e63f36f0864d7ce431cce61fe0118a"}, + {file = "grpcio-1.56.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c0bc9dda550785d23f4f025be614b7faa8d0293e10811f0f8536cf50435b7a30"}, + {file = "grpcio-1.56.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:d596408bab632ec7b947761e83ce6b3e7632e26b76d64c239ba66b554b7ee286"}, + {file = "grpcio-1.56.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76b6e6e1ee9bda32e6e933efd61c512e9a9f377d7c580977f090d1a9c78cca44"}, + {file = "grpcio-1.56.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7beb84ebd0a3f732625124b73969d12b7350c5d9d64ddf81ae739bbc63d5b1ed"}, + {file = "grpcio-1.56.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83ec714bbbe9b9502177c842417fde39f7a267031e01fa3cd83f1ca49688f537"}, + {file = "grpcio-1.56.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4feee75565d1b5ab09cb3a5da672b84ca7f6dd80ee07a50f5537207a9af543a4"}, + {file = "grpcio-1.56.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b4638a796778329cc8e142e4f57c705adb286b3ba64e00b0fa91eeb919611be8"}, + {file = "grpcio-1.56.0-cp39-cp39-win32.whl", hash = "sha256:437af5a7673bca89c4bc0a993382200592d104dd7bf55eddcd141cef91f40bab"}, + {file = "grpcio-1.56.0-cp39-cp39-win_amd64.whl", hash = "sha256:4241a1c2c76e748023c834995cd916570e7180ee478969c2d79a60ce007bc837"}, + {file = "grpcio-1.56.0.tar.gz", hash = "sha256:4c08ee21b3d10315b8dc26f6c13917b20ed574cdbed2d2d80c53d5508fdcc0f2"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.56.0)"] + +[[package]] +name = "grpcio-tools" +version = "1.56.0" +description = "Protobuf code generator for gRPC" +optional = false +python-versions = ">=3.7" +files = [ + {file = "grpcio-tools-1.56.0.tar.gz", hash = "sha256:39f5877cea514b3da9f2683dfb3ffb45ef47b05f4ff39c287d7d61c5057f48b8"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:cdbae7312e6d132d38ec2c1611b8cafb783e0416cc5c6deae04efde5f16fb190"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:5f5c416b88d76fbdb548cfee0486928748816b700ece6e591006e5b1dc67598f"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:23e2ef1dc6a9bf766f091e2c52a68e54d0aff3548f94562e61fb0ac3874d514a"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8870ab60f8a76b4a7e43184ee03d28112b976d83c43d41cec821f47b3a297da2"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e59ab6c0bf4a8bb975553ad578d4425bd192775ae384f9406d77d31ad00f6efe"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b309659534b5d930f9ab6d521670c2dd86cb6ef7f47f37f73f96557e2ec13a49"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8115b416ea2cad8a87dc3aadfaf26da684e003c3770b12e7219b462505bb5b85"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-win32.whl", hash = "sha256:e4cb62a521efbca4cb1ad50233aa400574b3daaf6eb26707d661a0afe8191d92"}, + {file = "grpcio_tools-1.56.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d59009ed52220eb2d62f5cefa4e58dec930fb92fab27bb390c4cf1d360ac7e1"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:cd69107705794e815a8b262722c6fea995911cb1dfc1310abf63b476165335d6"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:2d1ee9e13ce135a6ed451b428ef14af131dc7df2551a5344ff4f8aee2d9fab99"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:142530b9fdfabe04f0c7e5dacd45b6c419d39704fa439cc0aabf73ea0d8f916d"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b7a4eb5003a29eecd71707589f93ae7e8fa2e681366a811b3f86695055d8666"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa6d9bdd75d3625dae38372b43696e159c10aa98719b4302b1e94f1ff7878d47"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c43b4fe8c8df4c52d3106bba2cf427f0e46bbebb80e127fbbc3134db0fead7be"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:168940a4a955b6c65da978dbf62e1c36e3a311bb27f649fd201a228e2583a6d4"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-win32.whl", hash = "sha256:3a4b06169493f9454a7f2516c5d41b566d9734e553bbc505f2a7837f7f4a2df1"}, + {file = "grpcio_tools-1.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:1bd361fcc967c21672ba855fc77ea0e7afa51664033a746df96545f84edc4670"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e6bcb194b81e372411494d8ed69fab89aa3452b7275fce4f7917fbe7b04fb72"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:02b23a12b91287ebea14b3685735d1d675e77c3cd365ec1771c3e9afbeba1ec6"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:80d75856f8ec949847386ad2f56a460f21c63bf82ce99ca5b6aa512c0b875fb1"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cffff0b4af80285fa49637d69b69d640eb775dc74b23635e4de5faad9e7e744"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3de6c08b545920a39b31ed13305f946c00b19ac1b13d26119f111b6360f22ccf"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:128bb13fe9a2681eeb08175f5fbc8e2d8953d7d0dd240e96f9244b9d2547a1aa"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b57f7f01eafbfe3a293f2efffb675774dbe4074c4627975ec4dc4aa5766801fb"}, + {file = "grpcio_tools-1.56.0-cp37-cp37m-win_amd64.whl", hash = "sha256:282176066fb082ad21c403b84f9d6b440a20482e6f52b83bb2adf54d6fdcae9f"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:d9b8d1c42854d3433c058795f52b1418b53dd8c1e9811fecb1312202e803a2c5"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:accf713f51da74b1a18aa4b31df0ab135510704661f735a938081777b79a4c25"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:ac33fd2d02d24101ea389be8e05b928acb58be56403d4ebc3aecfab473fa4a25"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4acdc7b957abfd76581717f0ac8e4408e0a85b7d0ac8d2cdf4d964f16926b897"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79291bfb1fe5f21d99f4839f43d3c5d44c5402c830a24dbb2811d785dd21264b"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0a8767e4de0f573c678313c5de075ac0e163a192bb135018e45015a22f234387"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:96fe2f7f5805d88cb7f2e3e3502550b2883dfab0f9efcf3cbd444942cf2ee1da"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-win32.whl", hash = "sha256:21cf32ccffd4f1800b0dcdf58aa1fc7f626795c9da784c3d817c944edcf2d3ae"}, + {file = "grpcio_tools-1.56.0-cp38-cp38-win_amd64.whl", hash = "sha256:f3ab1a9fad636302f7307d143f64a9fbd11bc041652bf53bb016006e9a5ca820"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:8989d363ac1996238fee61c8f5663f15a8fc362cb1e758c4a686b76cb457cd70"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:11cdd9cbf0c09c3a761c6f59dfd7128104be7cd393334efe386d4fc3f990ee1a"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5fd4c005a4afec16578849bc522ddf3298d6d499b3d37bf51314b086c714cdd5"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7302acaa07cf4966c926fcd6a60c8d30a697f730c38168bf83e1519b464115b"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1c43d185ebf904c3deec23c36ca2ba4e95db999cf00fc8f85eda4551622a26"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b12bb8c1d408ae40e4c806a3a8ebda2d107310e46696e1da13d0dc3f91fbd19d"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:781cf09e4d5c9288708f6ec9c3eae64d9d5a0f4c46c7ebe70ebb7ab4f6384789"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-win32.whl", hash = "sha256:c62f07452dee3f1ed23aeaef821797c5e516f79535e97fe6a6b0a0ee8db1cc91"}, + {file = "grpcio_tools-1.56.0-cp39-cp39-win_amd64.whl", hash = "sha256:7f063443870650e55012fdb3a58ff4ce5f4042b81dad6b749333ee8146157511"}, +] + +[package.dependencies] +grpcio = ">=1.56.0" +protobuf = ">=4.21.6,<5.0dev" +setuptools = "*" + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "h2" +version = "4.1.0" +description = "HTTP/2 State-Machine based protocol implementation" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, + {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, +] + +[package.dependencies] +hpack = ">=4.0,<5" +hyperframe = ">=6.0,<7" + +[[package]] +name = "hnswlib" +version = "0.7.0" +description = "hnswlib" +optional = false +python-versions = "*" +files = [ + {file = "hnswlib-0.7.0.tar.gz", hash = "sha256:bc459668e7e44bb7454b256b90c98c5af750653919d9a91698dafcf416cf64c4"}, +] + +[package.dependencies] +numpy = "*" + +[[package]] +name = "hpack" +version = "4.0.0" +description = "Pure-Python HPACK header compression" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] + +[[package]] +name = "httpcore" +version = "0.16.3" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.7" +files = [ + {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, + {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, +] + +[package.dependencies] +anyio = ">=3.0,<5.0" +certifi = "*" +h11 = ">=0.13,<0.15" +sniffio = "==1.*" + +[package.extras] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httptools" +version = "0.6.0" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.5.0" +files = [ + {file = "httptools-0.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:818325afee467d483bfab1647a72054246d29f9053fd17cc4b86cda09cc60339"}, + {file = "httptools-0.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72205730bf1be875003692ca54a4a7c35fac77b4746008966061d9d41a61b0f5"}, + {file = "httptools-0.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33eb1d4e609c835966e969a31b1dedf5ba16b38cab356c2ce4f3e33ffa94cad3"}, + {file = "httptools-0.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdc6675ec6cb79d27e0575750ac6e2b47032742e24eed011b8db73f2da9ed40"}, + {file = "httptools-0.6.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:463c3bc5ef64b9cf091be9ac0e0556199503f6e80456b790a917774a616aff6e"}, + {file = "httptools-0.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82f228b88b0e8c6099a9c4757ce9fdbb8b45548074f8d0b1f0fc071e35655d1c"}, + {file = "httptools-0.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:0781fedc610293a2716bc7fa142d4c85e6776bc59d617a807ff91246a95dea35"}, + {file = "httptools-0.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:721e503245d591527cddd0f6fd771d156c509e831caa7a57929b55ac91ee2b51"}, + {file = "httptools-0.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:274bf20eeb41b0956e34f6a81f84d26ed57c84dd9253f13dcb7174b27ccd8aaf"}, + {file = "httptools-0.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:259920bbae18740a40236807915def554132ad70af5067e562f4660b62c59b90"}, + {file = "httptools-0.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03bfd2ae8a2d532952ac54445a2fb2504c804135ed28b53fefaf03d3a93eb1fd"}, + {file = "httptools-0.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f959e4770b3fc8ee4dbc3578fd910fab9003e093f20ac8c621452c4d62e517cb"}, + {file = "httptools-0.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6e22896b42b95b3237eccc42278cd72c0df6f23247d886b7ded3163452481e38"}, + {file = "httptools-0.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:38f3cafedd6aa20ae05f81f2e616ea6f92116c8a0f8dcb79dc798df3356836e2"}, + {file = "httptools-0.6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:47043a6e0ea753f006a9d0dd076a8f8c99bc0ecae86a0888448eb3076c43d717"}, + {file = "httptools-0.6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35a541579bed0270d1ac10245a3e71e5beeb1903b5fbbc8d8b4d4e728d48ff1d"}, + {file = "httptools-0.6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65d802e7b2538a9756df5acc062300c160907b02e15ed15ba035b02bce43e89c"}, + {file = "httptools-0.6.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:26326e0a8fe56829f3af483200d914a7cd16d8d398d14e36888b56de30bec81a"}, + {file = "httptools-0.6.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e41ccac9e77cd045f3e4ee0fc62cbf3d54d7d4b375431eb855561f26ee7a9ec4"}, + {file = "httptools-0.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4e748fc0d5c4a629988ef50ac1aef99dfb5e8996583a73a717fc2cac4ab89932"}, + {file = "httptools-0.6.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cf8169e839a0d740f3d3c9c4fa630ac1a5aaf81641a34575ca6773ed7ce041a1"}, + {file = "httptools-0.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5dcc14c090ab57b35908d4a4585ec5c0715439df07be2913405991dbb37e049d"}, + {file = "httptools-0.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d0b0571806a5168013b8c3d180d9f9d6997365a4212cb18ea20df18b938aa0b"}, + {file = "httptools-0.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb4a608c631f7dcbdf986f40af7a030521a10ba6bc3d36b28c1dc9e9035a3c0"}, + {file = "httptools-0.6.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:93f89975465133619aea8b1952bc6fa0e6bad22a447c6d982fc338fbb4c89649"}, + {file = "httptools-0.6.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:73e9d66a5a28b2d5d9fbd9e197a31edd02be310186db423b28e6052472dc8201"}, + {file = "httptools-0.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:22c01fcd53648162730a71c42842f73b50f989daae36534c818b3f5050b54589"}, + {file = "httptools-0.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f96d2a351b5625a9fd9133c95744e8ca06f7a4f8f0b8231e4bbaae2c485046a"}, + {file = "httptools-0.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72ec7c70bd9f95ef1083d14a755f321d181f046ca685b6358676737a5fecd26a"}, + {file = "httptools-0.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b703d15dbe082cc23266bf5d9448e764c7cb3fcfe7cb358d79d3fd8248673ef9"}, + {file = "httptools-0.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82c723ed5982f8ead00f8e7605c53e55ffe47c47465d878305ebe0082b6a1755"}, + {file = "httptools-0.6.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0a816bb425c116a160fbc6f34cece097fd22ece15059d68932af686520966bd"}, + {file = "httptools-0.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:dea66d94e5a3f68c5e9d86e0894653b87d952e624845e0b0e3ad1c733c6cc75d"}, + {file = "httptools-0.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:23b09537086a5a611fad5696fc8963d67c7e7f98cb329d38ee114d588b0b74cd"}, + {file = "httptools-0.6.0.tar.gz", hash = "sha256:9fc6e409ad38cbd68b177cd5158fc4042c796b82ca88d99ec78f07bed6c6b796"}, +] + +[package.extras] +test = ["Cython (>=0.29.24,<0.30.0)"] + +[[package]] +name = "httpx" +version = "0.23.3" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.7" +files = [ + {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, + {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, +] + +[package.dependencies] +certifi = "*" +h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} +httpcore = ">=0.15.0,<0.17.0" +rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "humanfriendly" +version = "10.0" +description = "Human friendly output for text interfaces using Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] + +[package.dependencies] +pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""} + +[[package]] +name = "hyperframe" +version = "6.0.1" +description = "HTTP/2 framing layer for Python" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, + {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, +] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "importlib-metadata" +version = "6.8.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "invoke" +version = "1.7.3" +description = "Pythonic task execution" +optional = false +python-versions = "*" +files = [ + {file = "invoke-1.7.3-py3-none-any.whl", hash = "sha256:d9694a865764dd3fd91f25f7e9a97fb41666e822bbb00e670091e3f43933574d"}, + {file = "invoke-1.7.3.tar.gz", hash = "sha256:41b428342d466a82135d5ab37119685a989713742be46e42a3a399d685579314"}, +] + +[[package]] +name = "isodate" +version = "0.6.1" +description = "An ISO 8601 date/time/duration parser and formatter" +optional = false +python-versions = "*" +files = [ + {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, + {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, +] + +[package.dependencies] +six = "*" + +[[package]] +name = "jaraco-classes" +version = "3.3.0" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jaraco.classes-3.3.0-py3-none-any.whl", hash = "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb"}, + {file = "jaraco.classes-3.3.0.tar.gz", hash = "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[[package]] +name = "jeepney" +version = "0.8.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, + {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, +] + +[package.extras] +test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["async_generator", "trio"] + +[[package]] +name = "keyring" +version = "24.2.0" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "keyring-24.2.0-py3-none-any.whl", hash = "sha256:4901caaf597bfd3bbd78c9a0c7c4c29fcd8310dab2cffefe749e916b6527acd6"}, + {file = "keyring-24.2.0.tar.gz", hash = "sha256:ca0746a19ec421219f4d713f848fa297a661a8a8c1504867e55bfb5e09091509"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +"jaraco.classes" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +completion = ["shtab"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[[package]] +name = "langchain" +version = "0.0.270" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain-0.0.270-py3-none-any.whl", hash = "sha256:ea1ee4bcf297871ea4fcdabd338cb90d9a767bf0e60501b7e6540eaf6ea31a9c"}, + {file = "langchain-0.0.270.tar.gz", hash = "sha256:9777af5dd7e2901e4d9e00e917c05475d8f8e6772dea0e743c2cfd1e16092fbc"}, +] + +[package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} +dataclasses-json = ">=0.5.7,<0.6.0" +langsmith = ">=0.0.21,<0.1.0" +numexpr = ">=2.8.4,<3.0.0" +numpy = ">=1,<2" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = ">=2,<3" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "amadeus (>=8.1.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.9,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clarifai (>=9.1.0)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=4,<5)", "deeplake (>=3.6.8,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.6,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "libdeeplake (>=0.0.60,<0.0.61)", "librosa (>=0.10.0.post2,<0.11.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "marqo (>=0.11.0,<0.12.0)", "momento (>=1.5.0,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "python-arango (>=7.5.9,<8.0.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.3.1,<2.0.0)", "rdflib (>=6.3.2,<7.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.4.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] +azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b6)", "openai (>=0,<1)"] +clarifai = ["clarifai (>=9.1.0)"] +cohere = ["cohere (>=4,<5)"] +docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] +embeddings = ["sentence-transformers (>=2,<3)"] +extended-testing = ["amazon-textract-caller (<2)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.0.7,<0.0.8)", "chardet (>=5.1.0,<6.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "openai (>=0,<1)", "openapi-schema-pydantic (>=1.2,<2.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tqdm (>=4.48.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +javascript = ["esprima (>=4.0.1,<5.0.0)"] +llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] +openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.4.0)"] +qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] +text-helpers = ["chardet (>=5.1.0,<6.0.0)"] + +[[package]] +name = "langsmith" +version = "0.0.25" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langsmith-0.0.25-py3-none-any.whl", hash = "sha256:d595435ad21fa6077550d7c85472935d1e8241afa042c1e29287d2c95c3ed151"}, + {file = "langsmith-0.0.25.tar.gz", hash = "sha256:e728c398fc1adaa0ed8abeb21f6a92d7fb19fe3ab49d3911c22b03dfe25935d6"}, +] + +[package.dependencies] +pydantic = ">=1,<3" +requests = ">=2,<3" + +[[package]] +name = "llama-index" +version = "0.5.4" +description = "Interface between LLMs and your data." +optional = false +python-versions = "*" +files = [ + {file = "llama_index-0.5.4.tar.gz", hash = "sha256:f6c556370f7f03039bc19be4ca594b00f38d7cea18399f6045bc776fa3a90d15"}, +] + +[package.dependencies] +dataclasses_json = "*" +langchain = "*" +numpy = "*" +openai = ">=0.26.4" +pandas = "*" +tenacity = ">=8.2.0,<9.0.0" +tiktoken = "*" + +[[package]] +name = "loguru" +version = "0.7.0" +description = "Python logging made (stupidly) simple" +optional = false +python-versions = ">=3.5" +files = [ + {file = "loguru-0.7.0-py3-none-any.whl", hash = "sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"}, + {file = "loguru-0.7.0.tar.gz", hash = "sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} +win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} + +[package.extras] +dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v0.990)", "pre-commit (==3.2.1)", "pytest (==6.1.2)", "pytest (==7.2.1)", "pytest-cov (==2.12.1)", "pytest-cov (==4.0.0)", "pytest-mypy-plugins (==1.10.1)", "pytest-mypy-plugins (==1.9.3)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.2.0)", "tox (==3.27.1)", "tox (==4.4.6)"] + +[[package]] +name = "lxml" +version = "4.9.3" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" +files = [ + {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, + {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, + {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, + {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, + {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, + {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, + {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, + {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, + {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, + {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, + {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, + {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, + {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, + {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, + {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, + {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, + {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, + {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, + {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, + {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, + {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, + {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, + {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, + {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, +] + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] +source = ["Cython (>=0.29.35)"] + +[[package]] +name = "lz4" +version = "4.3.2" +description = "LZ4 Bindings for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "lz4-4.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1c4c100d99eed7c08d4e8852dd11e7d1ec47a3340f49e3a96f8dfbba17ffb300"}, + {file = "lz4-4.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:edd8987d8415b5dad25e797043936d91535017237f72fa456601be1479386c92"}, + {file = "lz4-4.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7c50542b4ddceb74ab4f8b3435327a0861f06257ca501d59067a6a482535a77"}, + {file = "lz4-4.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f5614d8229b33d4a97cb527db2a1ac81308c6e796e7bdb5d1309127289f69d5"}, + {file = "lz4-4.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f00a9ba98f6364cadda366ae6469b7b3568c0cced27e16a47ddf6b774169270"}, + {file = "lz4-4.3.2-cp310-cp310-win32.whl", hash = "sha256:b10b77dc2e6b1daa2f11e241141ab8285c42b4ed13a8642495620416279cc5b2"}, + {file = "lz4-4.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:86480f14a188c37cb1416cdabacfb4e42f7a5eab20a737dac9c4b1c227f3b822"}, + {file = "lz4-4.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7c2df117def1589fba1327dceee51c5c2176a2b5a7040b45e84185ce0c08b6a3"}, + {file = "lz4-4.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1f25eb322eeb24068bb7647cae2b0732b71e5c639e4e4026db57618dcd8279f0"}, + {file = "lz4-4.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8df16c9a2377bdc01e01e6de5a6e4bbc66ddf007a6b045688e285d7d9d61d1c9"}, + {file = "lz4-4.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f571eab7fec554d3b1db0d666bdc2ad85c81f4b8cb08906c4c59a8cad75e6e22"}, + {file = "lz4-4.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7211dc8f636ca625abc3d4fb9ab74e5444b92df4f8d58ec83c8868a2b0ff643d"}, + {file = "lz4-4.3.2-cp311-cp311-win32.whl", hash = "sha256:867664d9ca9bdfce840ac96d46cd8838c9ae891e859eb98ce82fcdf0e103a947"}, + {file = "lz4-4.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:a6a46889325fd60b8a6b62ffc61588ec500a1883db32cddee9903edfba0b7584"}, + {file = "lz4-4.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a85b430138882f82f354135b98c320dafb96fc8fe4656573d95ab05de9eb092"}, + {file = "lz4-4.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65d5c93f8badacfa0456b660285e394e65023ef8071142e0dcbd4762166e1be0"}, + {file = "lz4-4.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b50f096a6a25f3b2edca05aa626ce39979d63c3b160687c8c6d50ac3943d0ba"}, + {file = "lz4-4.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:200d05777d61ba1ff8d29cb51c534a162ea0b4fe6d3c28be3571a0a48ff36080"}, + {file = "lz4-4.3.2-cp37-cp37m-win32.whl", hash = "sha256:edc2fb3463d5d9338ccf13eb512aab61937be50aa70734bcf873f2f493801d3b"}, + {file = "lz4-4.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:83acfacab3a1a7ab9694333bcb7950fbeb0be21660d236fd09c8337a50817897"}, + {file = "lz4-4.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a9eec24ec7d8c99aab54de91b4a5a149559ed5b3097cf30249b665689b3d402"}, + {file = "lz4-4.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:31d72731c4ac6ebdce57cd9a5cabe0aecba229c4f31ba3e2c64ae52eee3fdb1c"}, + {file = "lz4-4.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83903fe6db92db0be101acedc677aa41a490b561567fe1b3fe68695b2110326c"}, + {file = "lz4-4.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926b26db87ec8822cf1870efc3d04d06062730ec3279bbbd33ba47a6c0a5c673"}, + {file = "lz4-4.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e05afefc4529e97c08e65ef92432e5f5225c0bb21ad89dee1e06a882f91d7f5e"}, + {file = "lz4-4.3.2-cp38-cp38-win32.whl", hash = "sha256:ad38dc6a7eea6f6b8b642aaa0683253288b0460b70cab3216838747163fb774d"}, + {file = "lz4-4.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:7e2dc1bd88b60fa09b9b37f08553f45dc2b770c52a5996ea52b2b40f25445676"}, + {file = "lz4-4.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:edda4fb109439b7f3f58ed6bede59694bc631c4b69c041112b1b7dc727fffb23"}, + {file = "lz4-4.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ca83a623c449295bafad745dcd399cea4c55b16b13ed8cfea30963b004016c9"}, + {file = "lz4-4.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5ea0e788dc7e2311989b78cae7accf75a580827b4d96bbaf06c7e5a03989bd5"}, + {file = "lz4-4.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a98b61e504fb69f99117b188e60b71e3c94469295571492a6468c1acd63c37ba"}, + {file = "lz4-4.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4931ab28a0d1c133104613e74eec1b8bb1f52403faabe4f47f93008785c0b929"}, + {file = "lz4-4.3.2-cp39-cp39-win32.whl", hash = "sha256:ec6755cacf83f0c5588d28abb40a1ac1643f2ff2115481089264c7630236618a"}, + {file = "lz4-4.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:4caedeb19e3ede6c7a178968b800f910db6503cb4cb1e9cc9221157572139b49"}, + {file = "lz4-4.3.2.tar.gz", hash = "sha256:e1431d84a9cfb23e6773e72078ce8e65cad6745816d4cbf9ae67da5ea419acda"}, +] + +[package.extras] +docs = ["sphinx (>=1.6.0)", "sphinx-bootstrap-theme"] +flake8 = ["flake8"] +tests = ["psutil", "pytest (!=3.3.0)", "pytest-cov"] + +[[package]] +name = "marshmallow" +version = "3.20.1" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"}, + {file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] +tests = ["pytest", "pytz", "simplejson"] + +[[package]] +name = "marshmallow-enum" +version = "1.5.1" +description = "Enum field for Marshmallow" +optional = false +python-versions = "*" +files = [ + {file = "marshmallow-enum-1.5.1.tar.gz", hash = "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58"}, + {file = "marshmallow_enum-1.5.1-py2.py3-none-any.whl", hash = "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"}, +] + +[package.dependencies] +marshmallow = ">=2.0.0" + +[[package]] +name = "monotonic" +version = "1.6" +description = "An implementation of time.monotonic() for Python 2 & < 3.3" +optional = false +python-versions = "*" +files = [ + {file = "monotonic-1.6-py2.py3-none-any.whl", hash = "sha256:68687e19a14f11f26d140dd5c86f3dba4bf5df58003000ed467e0e2a69bca96c"}, + {file = "monotonic-1.6.tar.gz", hash = "sha256:3a55207bcfed53ddd5c5bae174524062935efed17792e9de2ad0205ce9ad63f7"}, +] + +[[package]] +name = "more-itertools" +version = "10.1.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.8" +files = [ + {file = "more-itertools-10.1.0.tar.gz", hash = "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a"}, + {file = "more_itertools-10.1.0-py3-none-any.whl", hash = "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6"}, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +description = "Python library for arbitrary-precision floating-point arithmetic" +optional = false +python-versions = "*" +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[package.extras] +develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] +docs = ["sphinx"] +gmpy = ["gmpy2 (>=2.1.0a4)"] +tests = ["pytest (>=4.6)"] + +[[package]] +name = "msal" +version = "1.23.0" +description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." +optional = false +python-versions = "*" +files = [ + {file = "msal-1.23.0-py2.py3-none-any.whl", hash = "sha256:3342e0837a047007f9d479e814b559c3219767453d57920dc40a31986862048b"}, + {file = "msal-1.23.0.tar.gz", hash = "sha256:25c9a33acf84301f93d1fdbe9f1a9c60cd38af0d5fffdbfa378138fc7bc1e86b"}, +] + +[package.dependencies] +cryptography = ">=0.6,<44" +PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} +requests = ">=2.0.0,<3" + +[package.extras] +broker = ["pymsalruntime (>=0.13.2,<0.14)"] + +[[package]] +name = "msal-extensions" +version = "1.0.0" +description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." +optional = false +python-versions = "*" +files = [ + {file = "msal-extensions-1.0.0.tar.gz", hash = "sha256:c676aba56b0cce3783de1b5c5ecfe828db998167875126ca4b47dc6436451354"}, + {file = "msal_extensions-1.0.0-py2.py3-none-any.whl", hash = "sha256:91e3db9620b822d0ed2b4d1850056a0f133cba04455e62f11612e40f5502f2ee"}, +] + +[package.dependencies] +msal = ">=0.4.1,<2.0.0" +portalocker = [ + {version = ">=1.0,<3", markers = "python_version >= \"3.5\" and platform_system != \"Windows\""}, + {version = ">=1.6,<3", markers = "python_version >= \"3.5\" and platform_system == \"Windows\""}, +] + +[[package]] +name = "multidict" +version = "6.0.4" +description = "multidict implementation" +optional = false +python-versions = ">=3.7" +files = [ + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, + {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, + {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, + {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, + {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, + {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, + {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, + {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, + {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, + {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, + {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, + {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, + {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numexpr" +version = "2.8.5" +description = "Fast numerical expression evaluator for NumPy" +optional = false +python-versions = ">=3.7" +files = [ + {file = "numexpr-2.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51f3ab160c3847ebcca93cd88f935a7802b54a01ab63fe93152994a64d7a6cf2"}, + {file = "numexpr-2.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:de29c77f674e4eb8f0846525a475cab64008c227c8bc4ba5153ab3f72441cc63"}, + {file = "numexpr-2.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf85ba1327eb87ec82ae7936f13c8850fb969a0ca34f3ba9fa3897c09d5c80d7"}, + {file = "numexpr-2.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c00be69f747f44a631830215cab482f0f77f75af2925695adff57c1cc0f9a68"}, + {file = "numexpr-2.8.5-cp310-cp310-win32.whl", hash = "sha256:c46350dcdb93e32f033eea5a21269514ffcaf501d9abd6036992d37e48a308b0"}, + {file = "numexpr-2.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:894b027438b8ec88dea32a19193716c79f4ff8ddb92302dcc9731b51ba3565a8"}, + {file = "numexpr-2.8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6df184d40d4cf9f21c71f429962f39332f7398147762588c9f3a5c77065d0c06"}, + {file = "numexpr-2.8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:178b85ad373c6903e55d75787d61b92380439b70d94b001cb055a501b0821335"}, + {file = "numexpr-2.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:578fe4008e4d5d6ff01bbeb2d7b7ba1ec658a5cda9c720cd26a9a8325f8ef438"}, + {file = "numexpr-2.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef621b4ee366a5c6a484f6678c9259f5b826569f8bfa0b89ba2306d5055468bb"}, + {file = "numexpr-2.8.5-cp311-cp311-win32.whl", hash = "sha256:dd57ab1a3d3aaa9274aff1cefbf93b8ddacc7973afef5b125905f6bf18fabab0"}, + {file = "numexpr-2.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:783324ba40eb804ecfc9ebae86120a1e339ab112d0ab8a1f0d48a26354d5bf9b"}, + {file = "numexpr-2.8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:183d5430db76826e54465c69db93a3c6ecbf03cda5aa1bb96eaad0147e9b68dc"}, + {file = "numexpr-2.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ce106f92ccea5b07b1d6f2f3c4370f05edf27691dc720a63903484a2137e48"}, + {file = "numexpr-2.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b594dc9e2d6291a0bc5c065e6d9caf3eee743b5663897832e9b17753c002947a"}, + {file = "numexpr-2.8.5-cp37-cp37m-win32.whl", hash = "sha256:62b4faf8e0627673b0210a837792bddd23050ecebc98069ab23eb0633ff1ef5f"}, + {file = "numexpr-2.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:db5c65417d69414f1ab31302ea01d3548303ef31209c38b4849d145be4e1d1ba"}, + {file = "numexpr-2.8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb36ffcfa1606e41aa08d559b4277bcad0e16b83941d1a4fee8d2bd5a34f8e0e"}, + {file = "numexpr-2.8.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:34af2a0e857d02a4bc5758bc037a777d50dacb13bcd57c7905268a3e44994ed6"}, + {file = "numexpr-2.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a8dad2bfaad5a5c34a2e8bbf62b9df1dfab266d345fda1feb20ff4e264b347a"}, + {file = "numexpr-2.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93f5a866cd13a808bc3d3a9c487d94cd02eec408b275ff0aa150f2e8e5191f8"}, + {file = "numexpr-2.8.5-cp38-cp38-win32.whl", hash = "sha256:558390fea6370003ac749ed9d0f38d708aa096f5dcb707ddb6e0ca5a0dd37da1"}, + {file = "numexpr-2.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:55983806815035eb63c5039520688c49536bb7f3cc3fc1d7d64c6a00cf3f353e"}, + {file = "numexpr-2.8.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1510da20e6f5f45333610b1ded44c566e2690c6c437c84f2a212ca09627c7e01"}, + {file = "numexpr-2.8.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e8b5bf7bcb4e8dcd66522d8fc96e1db7278f901cb4fd2e155efbe62a41dde08"}, + {file = "numexpr-2.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ed0e1c1ef5f34381448539f1fe9015906d21c9cfa2797c06194d4207dadb465"}, + {file = "numexpr-2.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aea6ab45c87c0a7041183c08a798f0ad4d7c5eccbce20cfe79ce6f1a45ef3702"}, + {file = "numexpr-2.8.5-cp39-cp39-win32.whl", hash = "sha256:cbfd833ee5fdb0efb862e152aee7e6ccea9c596d5c11d22604c2e6307bff7cad"}, + {file = "numexpr-2.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:283ce8609a7ccbadf91a68f3484558b3e36d27c93c98a41ec205efb0ab43c872"}, + {file = "numexpr-2.8.5.tar.gz", hash = "sha256:45ed41e55a0abcecf3d711481e12a5fb7a904fe99d42bc282a17cc5f8ea510be"}, +] + +[package.dependencies] +numpy = ">=1.13.3" + +[[package]] +name = "numpy" +version = "1.25.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, + {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, + {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, + {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, + {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, + {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, + {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, + {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, + {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, + {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, + {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, + {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, +] + +[[package]] +name = "onnxruntime" +version = "1.15.1" +description = "ONNX Runtime is a runtime accelerator for Machine Learning models" +optional = false +python-versions = "*" +files = [ + {file = "onnxruntime-1.15.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:baad59e6a763237fa39545325d29c16f98b8a45d2dfc524c67631e2e3ba44d16"}, + {file = "onnxruntime-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:568c2db848f619a0a93e843c028e9fb4879929d40b04bd60f9ba6eb8d2e93421"}, + {file = "onnxruntime-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69088d7784bb04dedfd9e883e2c96e4adf8ae0451acdd0abb78d68f59ecc6d9d"}, + {file = "onnxruntime-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cef43737b2cd886d5d718d100f56ec78c9c476c5db5f8f946e95024978fe754"}, + {file = "onnxruntime-1.15.1-cp310-cp310-win32.whl", hash = "sha256:79d7e65abb44a47c633ede8e53fe7b9756c272efaf169758c482c983cca98d7e"}, + {file = "onnxruntime-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:8bc4c47682933a7a2c79808688aad5f12581305e182be552de50783b5438e6bd"}, + {file = "onnxruntime-1.15.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:652b2cb777f76446e3cc41072dd3d1585a6388aeff92b9de656724bc22e241e4"}, + {file = "onnxruntime-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89b86dbed15740abc385055a29c9673a212600248d702737ce856515bdeddc88"}, + {file = "onnxruntime-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed5cdd9ee748149a57f4cdfa67187a0d68f75240645a3c688299dcd08742cc98"}, + {file = "onnxruntime-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f748cce6a70ed38c19658615c55f4eedb9192765a4e9c4bd2682adfe980698d"}, + {file = "onnxruntime-1.15.1-cp311-cp311-win32.whl", hash = "sha256:e0312046e814c40066e7823da58075992d51364cbe739eeeb2345ec440c3ac59"}, + {file = "onnxruntime-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:f0980969689cb956c22bd1318b271e1be260060b37f3ddd82c7d63bd7f2d9a79"}, + {file = "onnxruntime-1.15.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:345986cfdbd6f4b20a89b6a6cd9abd3e2ced2926ae0b6e91fefa8149f95c0f09"}, + {file = "onnxruntime-1.15.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d7b3ad75e040f1e95757f69826a11051737b31584938a26d466a0234c6de98"}, + {file = "onnxruntime-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3603d07b829bcc1c14963a76103e257aade8861eb208173b300cc26e118ec2f8"}, + {file = "onnxruntime-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3df0625b9295daf1f7409ea55f72e1eeb38d54f5769add53372e79ddc3cf98d"}, + {file = "onnxruntime-1.15.1-cp38-cp38-win32.whl", hash = "sha256:f68b47fdf1a0406c0292f81ac993e2a2ae3e8b166b436d590eb221f64e8e187a"}, + {file = "onnxruntime-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:52d762d297cc3f731f54fa65a3e329b813164970671547bef6414d0ed52765c9"}, + {file = "onnxruntime-1.15.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:99228f9f03dc1fc8af89a28c9f942e8bd3e97e894e263abe1a32e4ddb1f6363b"}, + {file = "onnxruntime-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:45db7f96febb0cf23e3af147f35c4f8de1a37dd252d1cef853c242c2780250cd"}, + {file = "onnxruntime-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bafc112a36db25c821b90ab747644041cb4218f6575889775a2c12dd958b8c3"}, + {file = "onnxruntime-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:985693d18f2d46aa34fd44d7f65ff620660b2c8fa4b8ec365c2ca353f0fbdb27"}, + {file = "onnxruntime-1.15.1-cp39-cp39-win32.whl", hash = "sha256:708eb31b0c04724bf0f01c1309a9e69bbc09b85beb750e5662c8aed29f1ff9fd"}, + {file = "onnxruntime-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:73d6de4c42dfde1e9dbea04773e6dc23346c8cda9c7e08c6554fafc97ac60138"}, +] + +[package.dependencies] +coloredlogs = "*" +flatbuffers = "*" +numpy = ">=1.21.6" +packaging = "*" +protobuf = "*" +sympy = "*" + +[[package]] +name = "openai" +version = "0.27.8" +description = "Python client library for the OpenAI API" +optional = false +python-versions = ">=3.7.1" +files = [ + {file = "openai-0.27.8-py3-none-any.whl", hash = "sha256:e0a7c2f7da26bdbe5354b03c6d4b82a2f34bd4458c7a17ae1a7092c3e397e03c"}, + {file = "openai-0.27.8.tar.gz", hash = "sha256:2483095c7db1eee274cebac79e315a986c4e55207bb4fa7b82d185b3a2ed9536"}, +] + +[package.dependencies] +aiohttp = "*" +requests = ">=2.20" +tqdm = "*" + +[package.extras] +datalib = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] +dev = ["black (>=21.6b0,<22.0)", "pytest (==6.*)", "pytest-asyncio", "pytest-mock"] +embeddings = ["matplotlib", "numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "plotly", "scikit-learn (>=1.0.2)", "scipy", "tenacity (>=8.0.1)"] +wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "wandb"] + +[[package]] +name = "overrides" +version = "7.4.0" +description = "A decorator to automatically detect mismatch when overriding a method." +optional = false +python-versions = ">=3.6" +files = [ + {file = "overrides-7.4.0-py3-none-any.whl", hash = "sha256:3ad24583f86d6d7a49049695efe9933e67ba62f0c7625d53c59fa832ce4b8b7d"}, + {file = "overrides-7.4.0.tar.gz", hash = "sha256:9502a3cca51f4fac40b5feca985b6703a5c1f6ad815588a7ca9e285b9dca6757"}, +] + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pandas" +version = "1.5.3" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, + {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, + {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, + {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, + {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, + {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, + {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, + {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, +] +python-dateutil = ">=2.8.1" +pytz = ">=2020.1" + +[package.extras] +test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] + +[[package]] +name = "pgvector" +version = "0.1.8" +description = "pgvector support for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pgvector-0.1.8-py2.py3-none-any.whl", hash = "sha256:99dce3a6580ef73863edb9b8441937671f4e1a09383826e6b0838176cd441a96"}, +] + +[package.dependencies] +numpy = "*" + +[[package]] +name = "pillow" +version = "10.0.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, + {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, + {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, + {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, + {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, + {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, + {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, + {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, + {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, + {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "pinecone-client" +version = "2.2.2" +description = "Pinecone client and SDK" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pinecone-client-2.2.2.tar.gz", hash = "sha256:391fe413754efd4e0ef00154b44271d63c4cdd4bedf088d23111a5725d863210"}, + {file = "pinecone_client-2.2.2-py3-none-any.whl", hash = "sha256:21fddb752668efee4d3c6b706346d9580e36a8b06b8d97afd60bd33ef2536e7e"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +loguru = ">=0.5.0" +numpy = ">=1.22.0" +python-dateutil = ">=2.5.3" +pyyaml = ">=5.4" +requests = ">=2.19.0" +tqdm = ">=4.64.1" +typing-extensions = ">=3.7.4" +urllib3 = ">=1.21.1" + +[package.extras] +grpc = ["googleapis-common-protos (>=1.53.0)", "grpc-gateway-protoc-gen-openapiv2 (==0.1.0)", "grpcio (>=1.44.0)", "lz4 (>=3.1.3)", "protobuf (>=3.19.5,<3.20.0)"] + +[[package]] +name = "pkginfo" +version = "1.9.6" +description = "Query metadata from sdists / bdists / installed packages." +optional = false +python-versions = ">=3.6" +files = [ + {file = "pkginfo-1.9.6-py3-none-any.whl", hash = "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546"}, + {file = "pkginfo-1.9.6.tar.gz", hash = "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"}, +] + +[package.extras] +testing = ["pytest", "pytest-cov"] + +[[package]] +name = "pluggy" +version = "1.2.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "portalocker" +version = "2.7.0" +description = "Wraps the portalocker recipe for easy usage" +optional = false +python-versions = ">=3.5" +files = [ + {file = "portalocker-2.7.0-py2.py3-none-any.whl", hash = "sha256:a07c5b4f3985c3cf4798369631fb7011adb498e2a46d8440efc75a8f29a0f983"}, + {file = "portalocker-2.7.0.tar.gz", hash = "sha256:032e81d534a88ec1736d03f780ba073f047a06c478b06e2937486f334e955c51"}, +] + +[package.dependencies] +pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} + +[package.extras] +docs = ["sphinx (>=1.7.1)"] +redis = ["redis"] +tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)"] + +[[package]] +name = "postgrest" +version = "0.10.6" +description = "PostgREST client for Python. This library provides an ORM interface to PostgREST." +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "postgrest-0.10.6-py3-none-any.whl", hash = "sha256:7302068ce3cd80e761e35d6d665d3e65632442488258e3299c008013119d7fe6"}, + {file = "postgrest-0.10.6.tar.gz", hash = "sha256:ee145d53ea8642a16fa7f42848443baa08ae1e6f41e071865f5f54bcb3b24aa3"}, +] + +[package.dependencies] +deprecation = ">=2.1.0,<3.0.0" +httpx = ">=0.23.0,<0.24.0" +pydantic = ">=1.9.0,<2.0.0" +strenum = ">=0.4.9,<0.5.0" + +[[package]] +name = "posthog" +version = "3.0.2" +description = "Integrate PostHog into any python application." +optional = false +python-versions = "*" +files = [ + {file = "posthog-3.0.2-py2.py3-none-any.whl", hash = "sha256:a8c0af6f2401fbe50f90e68c4143d0824b54e872de036b1c2f23b5abb39d88ce"}, + {file = "posthog-3.0.2.tar.gz", hash = "sha256:701fba6e446a4de687c6e861b587e7b7741955ad624bf34fe013c06a0fec6fb3"}, +] + +[package.dependencies] +backoff = ">=1.10.0" +monotonic = ">=1.5" +python-dateutil = ">2.1" +requests = ">=2.7,<3.0" +six = ">=1.5" + +[package.extras] +dev = ["black", "flake8", "flake8-print", "isort", "pre-commit"] +sentry = ["django", "sentry-sdk"] +test = ["coverage", "flake8", "freezegun (==0.3.15)", "mock (>=2.0.0)", "pylint", "pytest"] + +[[package]] +name = "protobuf" +version = "4.24.1" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "protobuf-4.24.1-cp310-abi3-win32.whl", hash = "sha256:d414199ca605eeb498adc4d2ba82aedc0379dca4a7c364ff9bc9a179aa28e71b"}, + {file = "protobuf-4.24.1-cp310-abi3-win_amd64.whl", hash = "sha256:5906c5e79ff50fe38b2d49d37db5874e3c8010826f2362f79996d83128a8ed9b"}, + {file = "protobuf-4.24.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:970c701ee16788d74f3de20938520d7a0aebc7e4fff37096a48804c80d2908cf"}, + {file = "protobuf-4.24.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fc361148e902949dcb953bbcb148c99fe8f8854291ad01107e4120361849fd0e"}, + {file = "protobuf-4.24.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:5d32363d14aca6e5c9e9d5918ad8fb65b091b6df66740ae9de50ac3916055e43"}, + {file = "protobuf-4.24.1-cp37-cp37m-win32.whl", hash = "sha256:df015c47d6855b8efa0b9be706c70bf7f050a4d5ac6d37fb043fbd95157a0e25"}, + {file = "protobuf-4.24.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d4af4fd9e9418e819be30f8df2a16e72fbad546a7576ac7f3653be92a6966d30"}, + {file = "protobuf-4.24.1-cp38-cp38-win32.whl", hash = "sha256:302e8752c760549ed4c7a508abc86b25d46553c81989343782809e1a062a2ef9"}, + {file = "protobuf-4.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:06437f0d4bb0d5f29e3d392aba69600188d4be5ad1e0a3370e581a9bf75a3081"}, + {file = "protobuf-4.24.1-cp39-cp39-win32.whl", hash = "sha256:0b2b224e9541fe9f046dd7317d05f08769c332b7e4c54d93c7f0f372dedb0b1a"}, + {file = "protobuf-4.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd39b9094a4cc003a1f911b847ab379f89059f478c0b611ba1215053e295132e"}, + {file = "protobuf-4.24.1-py3-none-any.whl", hash = "sha256:55dd644adc27d2a624339332755fe077c7f26971045b469ebb9732a69ce1f2ca"}, + {file = "protobuf-4.24.1.tar.gz", hash = "sha256:44837a5ed9c9418ad5d502f89f28ba102e9cd172b6668bc813f21716f9273348"}, +] + +[[package]] +name = "psycopg2" +version = "2.9.7" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +optional = false +python-versions = ">=3.6" +files = [ + {file = "psycopg2-2.9.7-cp310-cp310-win32.whl", hash = "sha256:1a6a2d609bce44f78af4556bea0c62a5e7f05c23e5ea9c599e07678995609084"}, + {file = "psycopg2-2.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:b22ed9c66da2589a664e0f1ca2465c29b75aaab36fa209d4fb916025fb9119e5"}, + {file = "psycopg2-2.9.7-cp311-cp311-win32.whl", hash = "sha256:44d93a0109dfdf22fe399b419bcd7fa589d86895d3931b01fb321d74dadc68f1"}, + {file = "psycopg2-2.9.7-cp311-cp311-win_amd64.whl", hash = "sha256:91e81a8333a0037babfc9fe6d11e997a9d4dac0f38c43074886b0d9dead94fe9"}, + {file = "psycopg2-2.9.7-cp37-cp37m-win32.whl", hash = "sha256:d1210fcf99aae6f728812d1d2240afc1dc44b9e6cba526a06fb8134f969957c2"}, + {file = "psycopg2-2.9.7-cp37-cp37m-win_amd64.whl", hash = "sha256:e9b04cbef584310a1ac0f0d55bb623ca3244c87c51187645432e342de9ae81a8"}, + {file = "psycopg2-2.9.7-cp38-cp38-win32.whl", hash = "sha256:d5c5297e2fbc8068d4255f1e606bfc9291f06f91ec31b2a0d4c536210ac5c0a2"}, + {file = "psycopg2-2.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:8275abf628c6dc7ec834ea63f6f3846bf33518907a2b9b693d41fd063767a866"}, + {file = "psycopg2-2.9.7-cp39-cp39-win32.whl", hash = "sha256:c7949770cafbd2f12cecc97dea410c514368908a103acf519f2a346134caa4d5"}, + {file = "psycopg2-2.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:b6bd7d9d3a7a63faae6edf365f0ed0e9b0a1aaf1da3ca146e6b043fb3eb5d723"}, + {file = "psycopg2-2.9.7.tar.gz", hash = "sha256:f00cc35bd7119f1fed17b85bd1007855194dde2cbd8de01ab8ebb17487440ad8"}, +] + +[[package]] +name = "psycopg2cffi" +version = "2.9.0" +description = ".. image:: https://travis-ci.org/chtd/psycopg2cffi.svg?branch=master" +optional = true +python-versions = "*" +files = [ + {file = "psycopg2cffi-2.9.0.tar.gz", hash = "sha256:7e272edcd837de3a1d12b62185eb85c45a19feda9e62fa1b120c54f9e8d35c52"}, +] + +[package.dependencies] +cffi = ">=1.0" +six = "*" + +[[package]] +name = "pulsar-client" +version = "3.2.0" +description = "Apache Pulsar Python client library" +optional = false +python-versions = "*" +files = [ + {file = "pulsar_client-3.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:da53bbe1903026ca1253d36a67bde0ae88513497091658aee8c5514c3e567483"}, + {file = "pulsar_client-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec595a71b7a25f1a72a1350efd6680a511b53253c3cac1911ba3d6c4d71fa64c"}, + {file = "pulsar_client-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3557c65463d74ec8d2864752389beb06761ab591dd134a164e0b1303c66719b"}, + {file = "pulsar_client-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d51dc76fec48217489bde95754ad58288c9389361de42f5a27d64e19840d27fb"}, + {file = "pulsar_client-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9ef2baf85311e0fe1b98342fdafbb93a1818a08ef999eaa524234fedf6f3b941"}, + {file = "pulsar_client-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:0928b02beda0c98e77178f4e30e962ddb8ee8c3320e4c7304a78b0796e976523"}, + {file = "pulsar_client-3.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:584f44b03474a69906be711a597a4d516263a55be31e49fc07be503dc8406821"}, + {file = "pulsar_client-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a637b9a3b30860c61e68a7b8ea650e0987d89e82f73b6a3df1ab662a6438fdda"}, + {file = "pulsar_client-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4a187fdc5febcf16f725179dcf2c476f31eeebd8353794d91754a3202dd5072"}, + {file = "pulsar_client-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5ff879f868cf1fd29db99f39fdb22b3ec3e749c648aca28526689756d922d1c5"}, + {file = "pulsar_client-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4a5f85d0cc414f739a5b51d843f213b54b2cd768c3a34f7c27cca410712b1f81"}, + {file = "pulsar_client-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:4fe748283848d829a80c0323558faeebea4c240d69fa58314ac90344f6999d17"}, + {file = "pulsar_client-3.2.0-cp37-cp37m-macosx_10_15_universal2.whl", hash = "sha256:06b91c26def86dbbc35be15257999fd8a2afbadf32983916ea3eef44f4d4cab4"}, + {file = "pulsar_client-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ec897bc8d232e6b118793378fc662a844334b829a28a1b4ad1c5fe8d019135"}, + {file = "pulsar_client-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa37c96c25c1b5aff3bad0fd0194b385ec190b2c67a2f439ac91577f81ae18d3"}, + {file = "pulsar_client-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d49cdd4d1b7fc2e80d100acf14e6fd3898f6e099e403fc56ed22a690245b2fec"}, + {file = "pulsar_client-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0058ca3191fd24528ccf94dba6f12e4093831454a2597166f96900d0717271bf"}, + {file = "pulsar_client-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:cb69b0411008e0b56df51de0aab20aa1c1a12aef3019b9ceba89afbae1f07fe2"}, + {file = "pulsar_client-3.2.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:f7d33e99602352df7a30707eab4e5781654602212fb618928bffb5523f2bcf35"}, + {file = "pulsar_client-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad1ac15a175ca90555c681a4d0134568771c6346b97a172f3ef14006556a50ae"}, + {file = "pulsar_client-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369e08ef1d5cb196dd9271039928800f90b4701a9c9df90bc068b44260d2fb11"}, + {file = "pulsar_client-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a52ba2b6736a2ebeed31b590e75d417dda149e333461655860efa84d898a3eb4"}, + {file = "pulsar_client-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c801334b3b569b23976481a2922bcea0c6dd990fc26544658dd9e9c8f78ca36"}, + {file = "pulsar_client-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:cd01fd419280e9013d1655bc53662248be2656b623b1506480e1a985aa7dadd2"}, + {file = "pulsar_client-3.2.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:0abe54d84db76435a6cd88ce27610352cabc7efae9fa3e7f874e032ec2ca0b3f"}, + {file = "pulsar_client-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a1b6a806eb4819d8cbab1c4ae44ebf2110a94204a46c365f5757e1455252f2"}, + {file = "pulsar_client-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34ea2a6b75ae0e303d522e5b57c75a4ff03dc18b9bfc14151fb14dfaf5866f17"}, + {file = "pulsar_client-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be6d3a9b2e1db3b6d1a7db5e13f7b4ed420674cf072cdb520fb004c4cd54c0af"}, + {file = "pulsar_client-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6b733e6239ffb505f7084df0175baf9d0215f14d0a02e9bbd1fdf71a2d6ea17"}, + {file = "pulsar_client-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:edc2135d02b4793efb086edca0ffaa6e8ac9133961c2cdc17ae487e0a53da481"}, +] + +[package.dependencies] +certifi = "*" + +[package.extras] +all = ["apache-bookkeeper-client (>=4.16.1)", "fastavro (==1.7.3)", "grpcio (>=1.8.2)", "prometheus-client", "protobuf (>=3.6.1,<=3.20.3)", "ratelimit"] +avro = ["fastavro (==1.7.3)"] +functions = ["apache-bookkeeper-client (>=4.16.1)", "grpcio (>=1.8.2)", "prometheus-client", "protobuf (>=3.6.1,<=3.20.3)", "ratelimit"] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pycryptodomex" +version = "3.18.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodomex-3.18.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:160a39a708c36fa0b168ab79386dede588e62aec06eb505add870739329aecc6"}, + {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c2953afebf282a444c51bf4effe751706b4d0d63d7ca2cc51db21f902aa5b84e"}, + {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ba95abd563b0d1b88401658665a260852a8e6c647026ee6a0a65589287681df8"}, + {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:192306cf881fe3467dda0e174a4f47bb3a8bb24b90c9cdfbdc248eec5fc0578c"}, + {file = "pycryptodomex-3.18.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:f9ab5ef0718f6a8716695dea16d83b671b22c45e9c0c78fd807c32c0192e54b5"}, + {file = "pycryptodomex-3.18.0-cp27-cp27m-win32.whl", hash = "sha256:50308fcdbf8345e5ec224a5502b4215178bdb5e95456ead8ab1a69ffd94779cb"}, + {file = "pycryptodomex-3.18.0-cp27-cp27m-win_amd64.whl", hash = "sha256:4d9379c684efea80fdab02a3eb0169372bca7db13f9332cb67483b8dc8b67c37"}, + {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5594a125dae30d60e94f37797fc67ce3c744522de7992c7c360d02fdb34918f8"}, + {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8ff129a5a0eb5ff16e45ca4fa70a6051da7f3de303c33b259063c19be0c43d35"}, + {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:3d9314ac785a5b75d5aaf924c5f21d6ca7e8df442e5cf4f0fefad4f6e284d422"}, + {file = "pycryptodomex-3.18.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:f237278836dda412a325e9340ba2e6a84cb0f56b9244781e5b61f10b3905de88"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac614363a86cc53d8ba44b6c469831d1555947e69ab3276ae8d6edc219f570f7"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:302a8f37c224e7b5d72017d462a2be058e28f7be627bdd854066e16722d0fc0c"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:6421d23d6a648e83ba2670a352bcd978542dad86829209f59d17a3f087f4afef"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84e105787f5e5d36ec6a581ff37a1048d12e638688074b2a00bcf402f9aa1c2"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6875eb8666f68ddbd39097867325bd22771f595b4e2b0149739b5623c8bf899b"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:27072a494ce621cc7a9096bbf60ed66826bb94db24b49b7359509e7951033e74"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1949e09ea49b09c36d11a951b16ff2a05a0ffe969dda1846e4686ee342fe8646"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6ed3606832987018615f68e8ed716a7065c09a0fe94afd7c9ca1b6777f0ac6eb"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-win32.whl", hash = "sha256:d56c9ec41258fd3734db9f5e4d2faeabe48644ba9ca23b18e1839b3bdf093222"}, + {file = "pycryptodomex-3.18.0-cp35-abi3-win_amd64.whl", hash = "sha256:e00a4bacb83a2627e8210cb353a2e31f04befc1155db2976e5e239dd66482278"}, + {file = "pycryptodomex-3.18.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2dc4eab20f4f04a2d00220fdc9258717b82d31913552e766d5f00282c031b70a"}, + {file = "pycryptodomex-3.18.0-pp27-pypy_73-win32.whl", hash = "sha256:75672205148bdea34669173366df005dbd52be05115e919551ee97171083423d"}, + {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bec6c80994d4e7a38312072f89458903b65ec99bed2d65aa4de96d997a53ea7a"}, + {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d35a8ffdc8b05e4b353ba281217c8437f02c57d7233363824e9d794cf753c419"}, + {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f0a46bee539dae4b3dfe37216f678769349576b0080fdbe431d19a02da42ff"}, + {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:71687eed47df7e965f6e0bf3cadef98f368d5221f0fb89d2132effe1a3e6a194"}, + {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:73d64b32d84cf48d9ec62106aa277dbe99ab5fbfd38c5100bc7bddd3beb569f7"}, + {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbdcce0a226d9205560a5936b05208c709b01d493ed8307792075dedfaaffa5f"}, + {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58fc0aceb9c961b9897facec9da24c6a94c5db04597ec832060f53d4d6a07196"}, + {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:215be2980a6b70704c10796dd7003eb4390e7be138ac6fb8344bf47e71a8d470"}, + {file = "pycryptodomex-3.18.0.tar.gz", hash = "sha256:3e3ecb5fe979e7c1bb0027e518340acf7ee60415d79295e5251d13c68dde576e"}, +] + +[[package]] +name = "pydantic" +version = "1.10.12" +description = "Data validation and settings management using python type hints" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic-1.10.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718"}, + {file = "pydantic-1.10.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe"}, + {file = "pydantic-1.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b"}, + {file = "pydantic-1.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d"}, + {file = "pydantic-1.10.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09"}, + {file = "pydantic-1.10.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed"}, + {file = "pydantic-1.10.12-cp310-cp310-win_amd64.whl", hash = "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a"}, + {file = "pydantic-1.10.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc"}, + {file = "pydantic-1.10.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405"}, + {file = "pydantic-1.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62"}, + {file = "pydantic-1.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494"}, + {file = "pydantic-1.10.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246"}, + {file = "pydantic-1.10.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33"}, + {file = "pydantic-1.10.12-cp311-cp311-win_amd64.whl", hash = "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f"}, + {file = "pydantic-1.10.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a"}, + {file = "pydantic-1.10.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565"}, + {file = "pydantic-1.10.12-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350"}, + {file = "pydantic-1.10.12-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303"}, + {file = "pydantic-1.10.12-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5"}, + {file = "pydantic-1.10.12-cp37-cp37m-win_amd64.whl", hash = "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8"}, + {file = "pydantic-1.10.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62"}, + {file = "pydantic-1.10.12-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb"}, + {file = "pydantic-1.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0"}, + {file = "pydantic-1.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c"}, + {file = "pydantic-1.10.12-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d"}, + {file = "pydantic-1.10.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33"}, + {file = "pydantic-1.10.12-cp38-cp38-win_amd64.whl", hash = "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47"}, + {file = "pydantic-1.10.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6"}, + {file = "pydantic-1.10.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523"}, + {file = "pydantic-1.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86"}, + {file = "pydantic-1.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1"}, + {file = "pydantic-1.10.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe"}, + {file = "pydantic-1.10.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb"}, + {file = "pydantic-1.10.12-cp39-cp39-win_amd64.whl", hash = "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d"}, + {file = "pydantic-1.10.12-py3-none-any.whl", hash = "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942"}, + {file = "pydantic-1.10.12.tar.gz", hash = "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303"}, +] + +[package.dependencies] +typing-extensions = ">=4.2.0" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pygments" +version = "2.16.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pykx" +version = "1.6.3" +description = "An interface between Python and q" +optional = false +python-versions = "*" +files = [ + {file = "pykx-1.6.3-cp310-cp310-macosx_10_10_arm64.macosx_11_0_arm64.macosx_12_0_arm64.macosx_13_0_arm64.whl", hash = "sha256:0c637045ad2082fb106ac68c84abc2487cfc6727febe87dfcaad5f68d1d8fffc"}, + {file = "pykx-1.6.3-cp310-cp310-macosx_10_10_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64.macosx_13_0_x86_64.whl", hash = "sha256:3246cae586ca3229310c6af6bb5f86b2817ab0a0fcb6f9d7c7bf613d961d5185"}, + {file = "pykx-1.6.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:46a9118208b41b60c48a9546ce68531d1b8a1eb90db37af84c7f2d63bbfbbdc3"}, + {file = "pykx-1.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c469006f9725dd71fc2e3df26fa1b02fe842ea74bf62df3779022c94907bb66"}, + {file = "pykx-1.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:002b7d0f122bad877f316a969feb92d1b27b0bfac333d5bdd6e96dca24bf8549"}, + {file = "pykx-1.6.3-cp311-cp311-macosx_10_10_arm64.macosx_11_0_arm64.macosx_12_0_arm64.macosx_13_0_arm64.whl", hash = "sha256:68feed45a0e971759a31dba4bcdc6c12f8f2e5ba8b998039aa91457135626dce"}, + {file = "pykx-1.6.3-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:c27a08281d64b7c5301126c8bd13c6a8a7b593c616bb49366d9f085279c35acb"}, + {file = "pykx-1.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:557ccb60bc263819c6281d3275652bfee29a7c0c553715a7bc05fdf491658e95"}, + {file = "pykx-1.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:ac03c54d5a17949cf15c5d518fd69164ddcf2066c0afd10c8573345132d2417d"}, + {file = "pykx-1.6.3-cp37-cp37m-macosx_10_10_arm64.macosx_11_0_arm64.macosx_12_0_arm64.macosx_13_0_arm64.whl", hash = "sha256:0db0edf6bcc17a70ec4c64dd396417002817de414b7f74ebf878cb063443f39c"}, + {file = "pykx-1.6.3-cp37-cp37m-macosx_10_10_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64.macosx_13_0_x86_64.whl", hash = "sha256:058d4350eb21deee68157aab6c76590a59de344d41f74769fbc1892cafd0889c"}, + {file = "pykx-1.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:2d6b051272d5ed022aaf9525f03ea7e30b8c04ddec97da33c4a82c3f86dda2fa"}, + {file = "pykx-1.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bea0d913536a72cf16c5f92ad870e8005a7b86e504a46ea109c852556f717ae"}, + {file = "pykx-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:a6ceb61394ee78b23b8f2dec817f6aeccc1e5e9bab004d16bba6a91ab6a4831b"}, + {file = "pykx-1.6.3-cp38-cp38-macosx_10_10_arm64.macosx_11_0_arm64.macosx_12_0_arm64.macosx_13_0_arm64.whl", hash = "sha256:964579a74eab88f5f0490fe19ee57e897b18799deca18dc0c71016d0b068a1c7"}, + {file = "pykx-1.6.3-cp38-cp38-macosx_10_10_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64.macosx_13_0_x86_64.whl", hash = "sha256:67b72a0ede76f33759085fdcdfa5351176153cfac6a24be702ed8a98e05692f7"}, + {file = "pykx-1.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:abba8e9753d8cd8de0172abb7953924a984f2fb8bee8be562776b451ca31a364"}, + {file = "pykx-1.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e181bbd5cfe5625271f7d974b6ef0c59e5cff2e1239d386b342c5204a04df95"}, + {file = "pykx-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:36ec0bdfca5c8b75e5fd1a9e6fd7c72b1c830201fda23af38ce7881e4588bd7a"}, + {file = "pykx-1.6.3-cp39-cp39-macosx_10_10_arm64.macosx_11_0_arm64.macosx_12_0_arm64.macosx_13_0_arm64.whl", hash = "sha256:9a31845b3a48c1647a852249007321f2da26febe923b37396a52a37d24ea8ab5"}, + {file = "pykx-1.6.3-cp39-cp39-macosx_10_10_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64.macosx_13_0_x86_64.whl", hash = "sha256:9d0fa5a07c82912563cfcf939340e5ae4e78acccbd481631869e9a5fae06252b"}, + {file = "pykx-1.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:4df15842c2c3c622161495231fcb2d8b1753f3a149f01bd9c2a798e7856467bb"}, + {file = "pykx-1.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3893921810e317212c1f6d56cfc67be373bcdcdcf5e7e410b1b2245e178a2345"}, + {file = "pykx-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:093c5a0a17cd3b1e0ca51a41d73c30d640cf01767680f426910217d164e087f2"}, +] + +[package.dependencies] +numpy = {version = ">=1.22,<2.0", markers = "python_version != \"3.7\""} +pandas = ">=1.2,<2.0" +pytz = ">=2022.1,<2023.0" + +[package.extras] +all = ["Cython (==3.0.0a11)", "black (==22.1.0)", "coverage[toml] (==6.3.2)", "flake8 (==4.0.1)", "flake8-bugbear (==22.1.11)", "flake8-colors (==0.1.9)", "flake8-docstrings (==1.6.0)", "flake8-import-order (==0.18.1)", "griffe (==0.14.0)", "jupyter (==1.0.0)", "markdown (==3.3.7)", "markdown-grid-tables (==0.0.1)", "mkdocs (==1.4.3)", "mkdocs-autorefs (==0.4.1)", "mkdocs-click (==0.5.0)", "mkdocs-exclude (==1.0.2)", "mkdocs-jupyter (==0.20.0)", "mkdocs-material (==8.1.10)", "mkdocs-render-swagger-plugin (==0.0.3)", "mkdocs-spellcheck (==0.2.0)", "mkdocstrings[python] (==0.18.0)", "pep8-naming (==0.12.1)", "plotly (==5.10.0)", "pyarrow (>=3.0.0,<10.0.0)", "pygments (==2.11)", "pymdown-extensions (==9.3)", "pyproject-flake8 (==0.0.1a2)", "pytest (==7.1.2)", "pytest-asyncio (==0.18.3)", "pytest-benchmark (==3.4.1)", "pytest-cov (==3.0.0)", "pytest-monitor (==1.6.5)", "pytest-randomly (==3.11.0)", "pytest-xdist (==2.5.0)"] +doc = ["black (==22.1.0)", "griffe (==0.14.0)", "jupyter (==1.0.0)", "markdown (==3.3.7)", "markdown-grid-tables (==0.0.1)", "mkdocs (==1.4.3)", "mkdocs-autorefs (==0.4.1)", "mkdocs-click (==0.5.0)", "mkdocs-exclude (==1.0.2)", "mkdocs-jupyter (==0.20.0)", "mkdocs-material (==8.1.10)", "mkdocs-render-swagger-plugin (==0.0.3)", "mkdocs-spellcheck (==0.2.0)", "mkdocstrings[python] (==0.18.0)", "pygments (==2.11)", "pymdown-extensions (==9.3)"] +lint = ["flake8 (==4.0.1)", "flake8-bugbear (==22.1.11)", "flake8-colors (==0.1.9)", "flake8-docstrings (==1.6.0)", "flake8-import-order (==0.18.1)", "pep8-naming (==0.12.1)", "pyproject-flake8 (==0.0.1a2)"] +pyarrow = ["pyarrow (>=3.0.0,<10.0.0)"] +test = ["Cython (==3.0.0a11)", "coverage[toml] (==6.3.2)", "plotly (==5.10.0)", "pytest (==7.1.2)", "pytest-asyncio (==0.18.3)", "pytest-benchmark (==3.4.1)", "pytest-cov (==3.0.0)", "pytest-monitor (==1.6.5)", "pytest-randomly (==3.11.0)", "pytest-xdist (==2.5.0)"] + +[[package]] +name = "pymilvus" +version = "2.2.15" +description = "Python Sdk for Milvus" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pymilvus-2.2.15-py3-none-any.whl", hash = "sha256:2c086a084f7bc34c35da39f3d473e2f91ffe43fc1a88a301f222f3ad09987226"}, + {file = "pymilvus-2.2.15.tar.gz", hash = "sha256:0e618708a64088f476712dfff40c2a3818f775e4c18b6c551cf2dd5d8863063b"}, +] + +[package.dependencies] +environs = "<=9.5.0" +grpcio = ">=1.49.1,<=1.56.0" +pandas = ">=1.2.4" +protobuf = ">=3.20.0" +ujson = ">=2.0.0" + +[[package]] +name = "pypdf2" +version = "3.0.1" +description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyPDF2-3.0.1.tar.gz", hash = "sha256:a74408f69ba6271f71b9352ef4ed03dc53a31aa404d29b5d31f53bfecfee1440"}, + {file = "pypdf2-3.0.1-py3-none-any.whl", hash = "sha256:d16e4205cfee272fbdc0568b68d82be796540b1537508cef59388f839c191928"}, +] + +[package.extras] +crypto = ["PyCryptodome"] +dev = ["black", "flit", "pip-tools", "pre-commit (<2.18.0)", "pytest-cov", "wheel"] +docs = ["myst_parser", "sphinx", "sphinx_rtd_theme"] +full = ["Pillow", "PyCryptodome"] +image = ["Pillow"] + +[[package]] +name = "pyreadline3" +version = "3.4.1" +description = "A python implementation of GNU readline." +optional = false +python-versions = "*" +files = [ + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, +] + +[[package]] +name = "pytest" +version = "7.4.0" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.20.3" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-asyncio-0.20.3.tar.gz", hash = "sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36"}, + {file = "pytest_asyncio-0.20.3-py3-none-any.whl", hash = "sha256:f129998b209d04fcc65c96fc85c11e5316738358909a8399e93be553d7656442"}, +] + +[package.dependencies] +pytest = ">=6.1.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "0.21.1" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-dotenv-0.21.1.tar.gz", hash = "sha256:1c93de8f636cde3ce377292818d0e440b6e45a82f215c3744979151fa8151c49"}, + {file = "python_dotenv-0.21.1-py3-none-any.whl", hash = "sha256:41e12e0318bebc859fcc4d97d4db8d20ad21721a6aa5047dd59f090391cb549a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-gitlab" +version = "3.15.0" +description = "Interact with GitLab API" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "python-gitlab-3.15.0.tar.gz", hash = "sha256:c9e65eb7612a9fbb8abf0339972eca7fd7a73d4da66c9b446ffe528930aff534"}, + {file = "python_gitlab-3.15.0-py3-none-any.whl", hash = "sha256:8f8d1c0d387f642eb1ac7bf5e8e0cd8b3dd49c6f34170cee3c7deb7d384611f3"}, +] + +[package.dependencies] +requests = ">=2.25.0" +requests-toolbelt = ">=0.10.1" + +[package.extras] +autocompletion = ["argcomplete (>=1.10.0,<3)"] +yaml = ["PyYaml (>=5.2)"] + +[[package]] +name = "python-multipart" +version = "0.0.6" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python_multipart-0.0.6-py3-none-any.whl", hash = "sha256:ee698bab5ef148b0a760751c261902cd096e57e10558e11aca17646b74ee1c18"}, + {file = "python_multipart-0.0.6.tar.gz", hash = "sha256:e9925a80bb668529f1b67c7fdb0a5dacdd7cbfc6fb0bff3ea443fe22bdd62132"}, +] + +[package.extras] +dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==1.7.3)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"] + +[[package]] +name = "python-pptx" +version = "0.6.21" +description = "Generate and manipulate Open XML PowerPoint (.pptx) files" +optional = false +python-versions = "*" +files = [ + {file = "python-pptx-0.6.21.tar.gz", hash = "sha256:7798a2aaf89563565b3c7120c0acfe9aff775db0db3580544e3bf4840c2e378f"}, +] + +[package.dependencies] +lxml = ">=3.1.0" +Pillow = ">=3.3.2" +XlsxWriter = ">=0.5.7" + +[[package]] +name = "python-semantic-release" +version = "7.33.2" +description = "Automatic Semantic Versioning for Python projects" +optional = false +python-versions = "*" +files = [ + {file = "python-semantic-release-7.33.2.tar.gz", hash = "sha256:c23b4bb746e9ddbe1ba7497c48f7d81403e67a14ceb37928ef667c1fbee5e324"}, + {file = "python_semantic_release-7.33.2-py3-none-any.whl", hash = "sha256:9e4990cc0a4dc37482ac5ec7fe6f70f71681228f68f0fa39370415701fdcf632"}, +] + +[package.dependencies] +click = ">=7,<9" +click-log = ">=0.3,<1" +dotty-dict = ">=1.3.0,<2" +gitpython = ">=3.0.8,<4" +invoke = ">=1.4.1,<2" +packaging = "*" +python-gitlab = ">=2,<4" +requests = ">=2.25,<3" +semver = ">=2.10,<3" +tomlkit = ">=0.10,<1.0" +twine = ">=3,<4" +wheel = "*" + +[package.extras] +dev = ["black", "isort", "tox"] +docs = ["Jinja2 (==3.0.3)", "Sphinx (==1.3.6)"] +mypy = ["mypy", "types-requests"] +test = ["coverage (>=5,<6)", "mock (==1.3.0)", "pytest (>=7,<8)", "pytest-mock (>=2,<3)", "pytest-xdist (>=1,<2)", "responses (==0.13.3)"] + +[[package]] +name = "pytz" +version = "2022.7.1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, + {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, +] + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "pywin32-ctypes" +version = "0.2.2" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, + {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "qdrant-client" +version = "1.4.0" +description = "Client library for the Qdrant vector search engine" +optional = false +python-versions = ">=3.7,<3.12" +files = [ + {file = "qdrant_client-1.4.0-py3-none-any.whl", hash = "sha256:2f9e563955b5163da98016f2ed38d9aea5058576c7c5844e9aa205d28155f56d"}, + {file = "qdrant_client-1.4.0.tar.gz", hash = "sha256:2e54f5a80eb1e7e67f4603b76365af4817af15fb3d0c0f44de4fd93afbbe5537"}, +] + +[package.dependencies] +grpcio = ">=1.41.0" +grpcio-tools = ">=1.41.0" +httpx = {version = ">=0.14.0", extras = ["http2"]} +numpy = {version = ">=1.21", markers = "python_version >= \"3.8\""} +portalocker = ">=2.7.0,<3.0.0" +pydantic = ">=1.10.8" +urllib3 = ">=1.26.14,<2.0.0" + +[[package]] +name = "readme-renderer" +version = "41.0" +description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse" +optional = false +python-versions = ">=3.8" +files = [ + {file = "readme_renderer-41.0-py3-none-any.whl", hash = "sha256:a38243d5b6741b700a850026e62da4bd739edc7422071e95fd5c4bb60171df86"}, + {file = "readme_renderer-41.0.tar.gz", hash = "sha256:4f4b11e5893f5a5d725f592c5a343e0dc74f5f273cb3dcf8c42d9703a27073f7"}, +] + +[package.dependencies] +bleach = ">=2.1.0" +docutils = ">=0.13.1" +Pygments = ">=2.5.1" + +[package.extras] +md = ["cmarkgfm (>=0.8.0)"] + +[[package]] +name = "realtime" +version = "1.0.0" +description = "" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "realtime-1.0.0-py3-none-any.whl", hash = "sha256:ceab9e292211ab08b5792ac52b3fa25398440031d5b369bd5799b8125056e2d8"}, + {file = "realtime-1.0.0.tar.gz", hash = "sha256:14e540c4a0cc2736ae83e0cbd7efbbfb8b736df1681df2b9141556cb4848502d"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1,<3.0.0" +typing-extensions = ">=4.2.0,<5.0.0" +websockets = ">=10.3,<11.0" + +[[package]] +name = "redis" +version = "4.5.4" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.7" +files = [ + {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, + {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] +name = "regex" +version = "2023.8.8" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.6" +files = [ + {file = "regex-2023.8.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:88900f521c645f784260a8d346e12a1590f79e96403971241e64c3a265c8ecdb"}, + {file = "regex-2023.8.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3611576aff55918af2697410ff0293d6071b7e00f4b09e005d614686ac4cd57c"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8a0ccc8f2698f120e9e5742f4b38dc944c38744d4bdfc427616f3a163dd9de5"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c662a4cbdd6280ee56f841f14620787215a171c4e2d1744c9528bed8f5816c96"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf0633e4a1b667bfe0bb10b5e53fe0d5f34a6243ea2530eb342491f1adf4f739"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:551ad543fa19e94943c5b2cebc54c73353ffff08228ee5f3376bd27b3d5b9800"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54de2619f5ea58474f2ac211ceea6b615af2d7e4306220d4f3fe690c91988a61"}, + {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ec4b3f0aebbbe2fc0134ee30a791af522a92ad9f164858805a77442d7d18570"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ae646c35cb9f820491760ac62c25b6d6b496757fda2d51be429e0e7b67ae0ab"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca339088839582d01654e6f83a637a4b8194d0960477b9769d2ff2cfa0fa36d2"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d9b6627408021452dcd0d2cdf8da0534e19d93d070bfa8b6b4176f99711e7f90"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:bd3366aceedf274f765a3a4bc95d6cd97b130d1dda524d8f25225d14123c01db"}, + {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7aed90a72fc3654fba9bc4b7f851571dcc368120432ad68b226bd593f3f6c0b7"}, + {file = "regex-2023.8.8-cp310-cp310-win32.whl", hash = "sha256:80b80b889cb767cc47f31d2b2f3dec2db8126fbcd0cff31b3925b4dc6609dcdb"}, + {file = "regex-2023.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:b82edc98d107cbc7357da7a5a695901b47d6eb0420e587256ba3ad24b80b7d0b"}, + {file = "regex-2023.8.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1e7d84d64c84ad97bf06f3c8cb5e48941f135ace28f450d86af6b6512f1c9a71"}, + {file = "regex-2023.8.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce0f9fbe7d295f9922c0424a3637b88c6c472b75eafeaff6f910494a1fa719ef"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06c57e14ac723b04458df5956cfb7e2d9caa6e9d353c0b4c7d5d54fcb1325c46"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7a9aaa5a1267125eef22cef3b63484c3241aaec6f48949b366d26c7250e0357"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b7408511fca48a82a119d78a77c2f5eb1b22fe88b0d2450ed0756d194fe7a9a"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14dc6f2d88192a67d708341f3085df6a4f5a0c7b03dec08d763ca2cd86e9f559"}, + {file = "regex-2023.8.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48c640b99213643d141550326f34f0502fedb1798adb3c9eb79650b1ecb2f177"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0085da0f6c6393428bf0d9c08d8b1874d805bb55e17cb1dfa5ddb7cfb11140bf"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:964b16dcc10c79a4a2be9f1273fcc2684a9eedb3906439720598029a797b46e6"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7ce606c14bb195b0e5108544b540e2c5faed6843367e4ab3deb5c6aa5e681208"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:40f029d73b10fac448c73d6eb33d57b34607f40116e9f6e9f0d32e9229b147d7"}, + {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b8e6ea6be6d64104d8e9afc34c151926f8182f84e7ac290a93925c0db004bfd"}, + {file = "regex-2023.8.8-cp311-cp311-win32.whl", hash = "sha256:942f8b1f3b223638b02df7df79140646c03938d488fbfb771824f3d05fc083a8"}, + {file = "regex-2023.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:51d8ea2a3a1a8fe4f67de21b8b93757005213e8ac3917567872f2865185fa7fb"}, + {file = "regex-2023.8.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e951d1a8e9963ea51efd7f150450803e3b95db5939f994ad3d5edac2b6f6e2b4"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704f63b774218207b8ccc6c47fcef5340741e5d839d11d606f70af93ee78e4d4"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22283c769a7b01c8ac355d5be0715bf6929b6267619505e289f792b01304d898"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91129ff1bb0619bc1f4ad19485718cc623a2dc433dff95baadbf89405c7f6b57"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de35342190deb7b866ad6ba5cbcccb2d22c0487ee0cbb251efef0843d705f0d4"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b993b6f524d1e274a5062488a43e3f9f8764ee9745ccd8e8193df743dbe5ee61"}, + {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3026cbcf11d79095a32d9a13bbc572a458727bd5b1ca332df4a79faecd45281c"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:293352710172239bf579c90a9864d0df57340b6fd21272345222fb6371bf82b3"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d909b5a3fff619dc7e48b6b1bedc2f30ec43033ba7af32f936c10839e81b9217"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3d370ff652323c5307d9c8e4c62efd1956fb08051b0e9210212bc51168b4ff56"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:b076da1ed19dc37788f6a934c60adf97bd02c7eea461b73730513921a85d4235"}, + {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e9941a4ada58f6218694f382e43fdd256e97615db9da135e77359da257a7168b"}, + {file = "regex-2023.8.8-cp36-cp36m-win32.whl", hash = "sha256:a8c65c17aed7e15a0c824cdc63a6b104dfc530f6fa8cb6ac51c437af52b481c7"}, + {file = "regex-2023.8.8-cp36-cp36m-win_amd64.whl", hash = "sha256:aadf28046e77a72f30dcc1ab185639e8de7f4104b8cb5c6dfa5d8ed860e57236"}, + {file = "regex-2023.8.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:423adfa872b4908843ac3e7a30f957f5d5282944b81ca0a3b8a7ccbbfaa06103"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ae594c66f4a7e1ea67232a0846649a7c94c188d6c071ac0210c3e86a5f92109"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e51c80c168074faa793685656c38eb7a06cbad7774c8cbc3ea05552d615393d8"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09b7f4c66aa9d1522b06e31a54f15581c37286237208df1345108fcf4e050c18"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e73e5243af12d9cd6a9d6a45a43570dbe2e5b1cdfc862f5ae2b031e44dd95a8"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:941460db8fe3bd613db52f05259c9336f5a47ccae7d7def44cc277184030a116"}, + {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f0ccf3e01afeb412a1a9993049cb160d0352dba635bbca7762b2dc722aa5742a"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2e9216e0d2cdce7dbc9be48cb3eacb962740a09b011a116fd7af8c832ab116ca"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5cd9cd7170459b9223c5e592ac036e0704bee765706445c353d96f2890e816c8"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4873ef92e03a4309b3ccd8281454801b291b689f6ad45ef8c3658b6fa761d7ac"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:239c3c2a339d3b3ddd51c2daef10874410917cd2b998f043c13e2084cb191684"}, + {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1005c60ed7037be0d9dea1f9c53cc42f836188227366370867222bda4c3c6bd7"}, + {file = "regex-2023.8.8-cp37-cp37m-win32.whl", hash = "sha256:e6bd1e9b95bc5614a7a9c9c44fde9539cba1c823b43a9f7bc11266446dd568e3"}, + {file = "regex-2023.8.8-cp37-cp37m-win_amd64.whl", hash = "sha256:9a96edd79661e93327cfeac4edec72a4046e14550a1d22aa0dd2e3ca52aec921"}, + {file = "regex-2023.8.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2181c20ef18747d5f4a7ea513e09ea03bdd50884a11ce46066bb90fe4213675"}, + {file = "regex-2023.8.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a2ad5add903eb7cdde2b7c64aaca405f3957ab34f16594d2b78d53b8b1a6a7d6"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9233ac249b354c54146e392e8a451e465dd2d967fc773690811d3a8c240ac601"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920974009fb37b20d32afcdf0227a2e707eb83fe418713f7a8b7de038b870d0b"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2b6c5dfe0929b6c23dde9624483380b170b6e34ed79054ad131b20203a1a63"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96979d753b1dc3b2169003e1854dc67bfc86edf93c01e84757927f810b8c3c93"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ae54a338191e1356253e7883d9d19f8679b6143703086245fb14d1f20196be9"}, + {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2162ae2eb8b079622176a81b65d486ba50b888271302190870b8cc488587d280"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c884d1a59e69e03b93cf0dfee8794c63d7de0ee8f7ffb76e5f75be8131b6400a"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf9273e96f3ee2ac89ffcb17627a78f78e7516b08f94dc435844ae72576a276e"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:83215147121e15d5f3a45d99abeed9cf1fe16869d5c233b08c56cdf75f43a504"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f7454aa427b8ab9101f3787eb178057c5250478e39b99540cfc2b889c7d0586"}, + {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0640913d2c1044d97e30d7c41728195fc37e54d190c5385eacb52115127b882"}, + {file = "regex-2023.8.8-cp38-cp38-win32.whl", hash = "sha256:0c59122ceccb905a941fb23b087b8eafc5290bf983ebcb14d2301febcbe199c7"}, + {file = "regex-2023.8.8-cp38-cp38-win_amd64.whl", hash = "sha256:c12f6f67495ea05c3d542d119d270007090bad5b843f642d418eb601ec0fa7be"}, + {file = "regex-2023.8.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82cd0a69cd28f6cc3789cc6adeb1027f79526b1ab50b1f6062bbc3a0ccb2dbc3"}, + {file = "regex-2023.8.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bb34d1605f96a245fc39790a117ac1bac8de84ab7691637b26ab2c5efb8f228c"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:987b9ac04d0b38ef4f89fbc035e84a7efad9cdd5f1e29024f9289182c8d99e09"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dd6082f4e2aec9b6a0927202c85bc1b09dcab113f97265127c1dc20e2e32495"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7eb95fe8222932c10d4436e7a6f7c99991e3fdd9f36c949eff16a69246dee2dc"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7098c524ba9f20717a56a8d551d2ed491ea89cbf37e540759ed3b776a4f8d6eb"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b694430b3f00eb02c594ff5a16db30e054c1b9589a043fe9174584c6efa8033"}, + {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2aeab3895d778155054abea5238d0eb9a72e9242bd4b43f42fd911ef9a13470"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:988631b9d78b546e284478c2ec15c8a85960e262e247b35ca5eaf7ee22f6050a"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:67ecd894e56a0c6108ec5ab1d8fa8418ec0cff45844a855966b875d1039a2e34"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:14898830f0a0eb67cae2bbbc787c1a7d6e34ecc06fbd39d3af5fe29a4468e2c9"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f2200e00b62568cfd920127782c61bc1c546062a879cdc741cfcc6976668dfcf"}, + {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9691a549c19c22d26a4f3b948071e93517bdf86e41b81d8c6ac8a964bb71e5a6"}, + {file = "regex-2023.8.8-cp39-cp39-win32.whl", hash = "sha256:6ab2ed84bf0137927846b37e882745a827458689eb969028af8032b1b3dac78e"}, + {file = "regex-2023.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5543c055d8ec7801901e1193a51570643d6a6ab8751b1f7dd9af71af467538bb"}, + {file = "regex-2023.8.8.tar.gz", hash = "sha256:fcbdc5f2b0f1cd0f6a56cdb46fe41d2cce1e644e3b68832f3eeebc5fb0f7712e"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "rfc3986" +version = "1.5.0" +description = "Validating URI References per RFC 3986" +optional = false +python-versions = "*" +files = [ + {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, +] + +[package.dependencies] +idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "secretstorage" +version = "3.3.3" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.6" +files = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + +[[package]] +name = "semver" +version = "2.13.0" +description = "Python helper for Semantic Versioning (http://semver.org/)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "semver-2.13.0-py2.py3-none-any.whl", hash = "sha256:ced8b23dceb22134307c1b8abfa523da14198793d9787ac838e70e29e77458d4"}, + {file = "semver-2.13.0.tar.gz", hash = "sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f"}, +] + +[[package]] +name = "setuptools" +version = "68.1.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, + {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "smmap" +version = "5.0.0" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.6" +files = [ + {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, + {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.20" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759b51346aa388c2e606ee206c0bc6f15a5299f6174d1e10cadbe4530d3c7a98"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1506e988ebeaaf316f183da601f24eedd7452e163010ea63dbe52dc91c7fc70e"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5768c268df78bacbde166b48be788b83dddaa2a5974b8810af422ddfe68a9bc8"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3f0dd6d15b6dc8b28a838a5c48ced7455c3e1fb47b89da9c79cc2090b072a50"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:243d0fb261f80a26774829bc2cee71df3222587ac789b7eaf6555c5b15651eed"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6eb6d77c31e1bf4268b4d61b549c341cbff9842f8e115ba6904249c20cb78a61"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-win32.whl", hash = "sha256:bcb04441f370cbe6e37c2b8d79e4af9e4789f626c595899d94abebe8b38f9a4d"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-win_amd64.whl", hash = "sha256:d32b5ffef6c5bcb452723a496bad2d4c52b346240c59b3e6dba279f6dcc06c14"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd81466bdbc82b060c3c110b2937ab65ace41dfa7b18681fdfad2f37f27acdd7"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6fe7d61dc71119e21ddb0094ee994418c12f68c61b3d263ebaae50ea8399c4d4"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4e571af672e1bb710b3cc1a9794b55bce1eae5aed41a608c0401885e3491179"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3364b7066b3c7f4437dd345d47271f1251e0cfb0aba67e785343cdbdb0fff08c"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1be86ccea0c965a1e8cd6ccf6884b924c319fcc85765f16c69f1ae7148eba64b"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1d35d49a972649b5080557c603110620a86aa11db350d7a7cb0f0a3f611948a0"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-win32.whl", hash = "sha256:27d554ef5d12501898d88d255c54eef8414576f34672e02fe96d75908993cf53"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-win_amd64.whl", hash = "sha256:411e7f140200c02c4b953b3dbd08351c9f9818d2bd591b56d0fa0716bd014f1e"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3c6aceebbc47db04f2d779db03afeaa2c73ea3f8dcd3987eb9efdb987ffa09a3"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d3f175410a6db0ad96b10bfbb0a5530ecd4fcf1e2b5d83d968dd64791f810ed"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8186be85da6587456c9ddc7bf480ebad1a0e6dcbad3967c4821233a4d4df57"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c3d99ba99007dab8233f635c32b5cd24fb1df8d64e17bc7df136cedbea427897"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:76fdfc0f6f5341987474ff48e7a66c3cd2b8a71ddda01fa82fedb180b961630a"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-win32.whl", hash = "sha256:d3793dcf5bc4d74ae1e9db15121250c2da476e1af8e45a1d9a52b1513a393459"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-win_amd64.whl", hash = "sha256:79fde625a0a55220d3624e64101ed68a059c1c1f126c74f08a42097a72ff66a9"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:599ccd23a7146e126be1c7632d1d47847fa9f333104d03325c4e15440fc7d927"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1a58052b5a93425f656675673ef1f7e005a3b72e3f2c91b8acca1b27ccadf5f4"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79543f945be7a5ada9943d555cf9b1531cfea49241809dd1183701f94a748624"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63e73da7fb030ae0a46a9ffbeef7e892f5def4baf8064786d040d45c1d6d1dc5"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ce5e81b800a8afc870bb8e0a275d81957e16f8c4b62415a7b386f29a0cb9763"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb0d3e94c2a84215532d9bcf10229476ffd3b08f481c53754113b794afb62d14"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-win32.whl", hash = "sha256:8dd77fd6648b677d7742d2c3cc105a66e2681cc5e5fb247b88c7a7b78351cf74"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-win_amd64.whl", hash = "sha256:6f8a934f9dfdf762c844e5164046a9cea25fabbc9ec865c023fe7f300f11ca4a"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:26a3399eaf65e9ab2690c07bd5cf898b639e76903e0abad096cd609233ce5208"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4cde2e1096cbb3e62002efdb7050113aa5f01718035ba9f29f9d89c3758e7e4e"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b09ba72e4e6d341bb5bdd3564f1cea6095d4c3632e45dc69375a1dbe4e26ec"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b74eeafaa11372627ce94e4dc88a6751b2b4d263015b3523e2b1e57291102f0"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:77d37c1b4e64c926fa3de23e8244b964aab92963d0f74d98cbc0783a9e04f501"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eefebcc5c555803065128401a1e224a64607259b5eb907021bf9b175f315d2a6"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-win32.whl", hash = "sha256:3423dc2a3b94125094897118b52bdf4d37daf142cbcf26d48af284b763ab90e9"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-win_amd64.whl", hash = "sha256:5ed61e3463021763b853628aef8bc5d469fe12d95f82c74ef605049d810f3267"}, + {file = "SQLAlchemy-2.0.20-py3-none-any.whl", hash = "sha256:63a368231c53c93e2b67d0c5556a9836fdcd383f7e3026a39602aad775b14acf"}, + {file = "SQLAlchemy-2.0.20.tar.gz", hash = "sha256:ca8a5ff2aa7f3ade6c498aaafce25b1eaeabe4e42b73e25519183e4566a16fc6"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +typing-extensions = ">=4.2.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx-oracle (>=7)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3-binary"] + +[[package]] +name = "starlette" +version = "0.25.0" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.7" +files = [ + {file = "starlette-0.25.0-py3-none-any.whl", hash = "sha256:774f1df1983fd594b9b6fb3ded39c2aa1979d10ac45caac0f4255cbe2acb8628"}, + {file = "starlette-0.25.0.tar.gz", hash = "sha256:854c71e73736c429c2bdb07801f2c76c9cba497e7c3cf4988fde5e95fe4cdb3c"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5" + +[package.extras] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] + +[[package]] +name = "storage3" +version = "0.5.3" +description = "Supabase Storage client for Python." +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "storage3-0.5.3-py3-none-any.whl", hash = "sha256:5dab88b8e91afadb72fbfde4ce8fb819d6324385624ceb9dca2927fb80b3b800"}, + {file = "storage3-0.5.3.tar.gz", hash = "sha256:0c8b356d61eb021d8fcb9ca94d124754f2738c75a73babef91b2f1f60b2a13c0"}, +] + +[package.dependencies] +httpx = ">=0.23,<0.25" +python-dateutil = ">=2.8.2,<3.0.0" +typing-extensions = ">=4.2.0,<5.0.0" + +[[package]] +name = "strenum" +version = "0.4.15" +description = "An Enum that inherits from str." +optional = false +python-versions = "*" +files = [ + {file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"}, + {file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"}, +] + +[package.extras] +docs = ["myst-parser[linkify]", "sphinx", "sphinx-rtd-theme"] +release = ["twine"] +test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] + +[[package]] +name = "supabase" +version = "1.0.3" +description = "Supabase client for Python." +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "supabase-1.0.3-py3-none-any.whl", hash = "sha256:2418113b7f503522d33fafd442e587356636bad6cb803f7e406e614acf2611d7"}, + {file = "supabase-1.0.3.tar.gz", hash = "sha256:c6eac0144b4236a61ccc72024a8e88d8f08979e47ea635307afae7fb4fc24bc6"}, +] + +[package.dependencies] +gotrue = ">=1.0.1,<2.0.0" +httpx = ">=0.23.0,<0.24.0" +postgrest = ">=0.10.6,<0.11.0" +python-semantic-release = "7.33.2" +realtime = ">=1.0.0,<2.0.0" +storage3 = ">=0.5.2,<0.6.0" +supafunc = ">=0.2.2,<0.3.0" + +[[package]] +name = "supafunc" +version = "0.2.2" +description = "Library for Supabase Functions" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "supafunc-0.2.2-py3-none-any.whl", hash = "sha256:a292812532cca05afc08d2cc040eea5bd79a8909e46051630620b67508070795"}, + {file = "supafunc-0.2.2.tar.gz", hash = "sha256:84f1f8d47297b0c8b712f1d8e20843406c025a203bba00cb7216e2163f295c24"}, +] + +[package.dependencies] +httpx = ">=0.23.0,<0.24.0" + +[[package]] +name = "sympy" +version = "1.12" +description = "Computer algebra system (CAS) in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, + {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"}, +] + +[package.dependencies] +mpmath = ">=0.19" + +[[package]] +name = "tenacity" +version = "8.2.3" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, + {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, +] + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + +[[package]] +name = "tiktoken" +version = "0.2.0" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tiktoken-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d06705b55bb5f6c194285b6d15ad31bd7586d44fe433be31bc3694cf8c70169c"}, + {file = "tiktoken-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29f2969945fc430f817c907f59a2da9e7b797fe65527ba5b9442618643a0dc86"}, + {file = "tiktoken-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:546455f27b6f7981d17de265b8b99e2fef980fbc3fde1d94b551f8354902000e"}, + {file = "tiktoken-0.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:54b5dc05f934ac68e8da4d2cc3acd77bc6968114b09669056f1bff12acc57049"}, + {file = "tiktoken-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5d3c48cb5649ce6bb2b207377dfdaa855e1e771b2e7f59fb251182c227573619"}, + {file = "tiktoken-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a55f983735745df9a87161d9e0ce9ef7d216039d389246be98c6d416bbb2452f"}, + {file = "tiktoken-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175de868393039a85fdf4c7cfb9b8883d1b248b9a3d9d0129d30414f5a59c333"}, + {file = "tiktoken-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6cd97b8cd14e3fe6647baa71c67f7f6b21a401fa996ccc3d93bf0ae02162af2"}, + {file = "tiktoken-0.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:806e2b8c0b9786c0e3212e8b3a6ac8f5840066c00a31b89e6c8d9ba0421e77d7"}, + {file = "tiktoken-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:57b753aa9813f06fa5a26da2622114bf9769a8d1dca1b276d3613ee15da5b09d"}, + {file = "tiktoken-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aa3c15b87bb2cea56ecc8fe4c7bf105c5c2dc4090c2df97c141100488297173a"}, + {file = "tiktoken-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bd98fc4a9ec967a089c62497f21277b53aa3e15a6fec731ac707eea4d5527938"}, + {file = "tiktoken-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab10ad3280f348a0d3bfea6d503c6aa84676b159692701bc7604e67129bd2135"}, + {file = "tiktoken-0.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:59296d495aa6aec375a75f07da44fabb9720632c9404b41b9cbfe95e17966345"}, + {file = "tiktoken-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:3b078e6109d522c5ffc52859520eef6c17a3b120ed52b79f48cae0badff08fe0"}, + {file = "tiktoken-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aef47e8037652b18d2665b77e1f9416d3a86ccd383b039d0dfcb7d92085cef6d"}, + {file = "tiktoken-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0f62f8349a5412962326dbc41c3823a1f381d8ab62afbee94480d8296499d8e"}, + {file = "tiktoken-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d0dbf7e1940427c11f0c8ab9046ad98d774850b21559b37ca60ff30d3a14620"}, + {file = "tiktoken-0.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8f1a7c6bec42a2fb5309a161d1b891fe5e181d4b620a962923a925f45fe25697"}, + {file = "tiktoken-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3349fd809d17b722814a6a700e4bc0125527f39057b57a02ed42f53bb4e6e2f5"}, + {file = "tiktoken-0.2.0.tar.gz", hash = "sha256:df41a3d478499757b5b32eae5e97657cf159d8d9e6764049dd7c3abb49e1b40f"}, +] + +[package.dependencies] +blobfile = ">=2" +regex = ">=2022.1.18" +requests = ">=2.26.0" + +[[package]] +name = "tokenizers" +version = "0.13.3" +description = "Fast and Customizable Tokenizers" +optional = false +python-versions = "*" +files = [ + {file = "tokenizers-0.13.3-cp310-cp310-macosx_10_11_x86_64.whl", hash = "sha256:f3835c5be51de8c0a092058a4d4380cb9244fb34681fd0a295fbf0a52a5fdf33"}, + {file = "tokenizers-0.13.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4ef4c3e821730f2692489e926b184321e887f34fb8a6b80b8096b966ba663d07"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5fd1a6a25353e9aa762e2aae5a1e63883cad9f4e997c447ec39d071020459bc"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee0b1b311d65beab83d7a41c56a1e46ab732a9eed4460648e8eb0bd69fc2d059"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ef4215284df1277dadbcc5e17d4882bda19f770d02348e73523f7e7d8b8d396"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4d53976079cff8a033f778fb9adca2d9d69d009c02fa2d71a878b5f3963ed30"}, + {file = "tokenizers-0.13.3-cp310-cp310-win32.whl", hash = "sha256:1f0e3b4c2ea2cd13238ce43548959c118069db7579e5d40ec270ad77da5833ce"}, + {file = "tokenizers-0.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:89649c00d0d7211e8186f7a75dfa1db6996f65edce4b84821817eadcc2d3c79e"}, + {file = "tokenizers-0.13.3-cp311-cp311-macosx_10_11_universal2.whl", hash = "sha256:56b726e0d2bbc9243872b0144515ba684af5b8d8cd112fb83ee1365e26ec74c8"}, + {file = "tokenizers-0.13.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:cc5c022ce692e1f499d745af293ab9ee6f5d92538ed2faf73f9708c89ee59ce6"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f55c981ac44ba87c93e847c333e58c12abcbb377a0c2f2ef96e1a266e4184ff2"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f247eae99800ef821a91f47c5280e9e9afaeed9980fc444208d5aa6ba69ff148"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b3e3215d048e94f40f1c95802e45dcc37c5b05eb46280fc2ccc8cd351bff839"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ba2b0bf01777c9b9bc94b53764d6684554ce98551fec496f71bc5be3a03e98b"}, + {file = "tokenizers-0.13.3-cp311-cp311-win32.whl", hash = "sha256:cc78d77f597d1c458bf0ea7c2a64b6aa06941c7a99cb135b5969b0278824d808"}, + {file = "tokenizers-0.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:ecf182bf59bd541a8876deccf0360f5ae60496fd50b58510048020751cf1724c"}, + {file = "tokenizers-0.13.3-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:0527dc5436a1f6bf2c0327da3145687d3bcfbeab91fed8458920093de3901b44"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07cbb2c307627dc99b44b22ef05ff4473aa7c7cc1fec8f0a8b37d8a64b1a16d2"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4560dbdeaae5b7ee0d4e493027e3de6d53c991b5002d7ff95083c99e11dd5ac0"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64064bd0322405c9374305ab9b4c07152a1474370327499911937fd4a76d004b"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8c6e2ab0f2e3d939ca66aa1d596602105fe33b505cd2854a4c1717f704c51de"}, + {file = "tokenizers-0.13.3-cp37-cp37m-win32.whl", hash = "sha256:6cc29d410768f960db8677221e497226e545eaaea01aa3613fa0fdf2cc96cff4"}, + {file = "tokenizers-0.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fc2a7fdf864554a0dacf09d32e17c0caa9afe72baf9dd7ddedc61973bae352d8"}, + {file = "tokenizers-0.13.3-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:8791dedba834c1fc55e5f1521be325ea3dafb381964be20684b92fdac95d79b7"}, + {file = "tokenizers-0.13.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:d607a6a13718aeb20507bdf2b96162ead5145bbbfa26788d6b833f98b31b26e1"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3791338f809cd1bf8e4fee6b540b36822434d0c6c6bc47162448deee3f77d425"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2f35f30e39e6aab8716f07790f646bdc6e4a853816cc49a95ef2a9016bf9ce6"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310204dfed5aa797128b65d63538a9837cbdd15da2a29a77d67eefa489edda26"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0f9b92ea052305166559f38498b3b0cae159caea712646648aaa272f7160963"}, + {file = "tokenizers-0.13.3-cp38-cp38-win32.whl", hash = "sha256:9a3fa134896c3c1f0da6e762d15141fbff30d094067c8f1157b9fdca593b5806"}, + {file = "tokenizers-0.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:8e7b0cdeace87fa9e760e6a605e0ae8fc14b7d72e9fc19c578116f7287bb873d"}, + {file = "tokenizers-0.13.3-cp39-cp39-macosx_10_11_x86_64.whl", hash = "sha256:00cee1e0859d55507e693a48fa4aef07060c4bb6bd93d80120e18fea9371c66d"}, + {file = "tokenizers-0.13.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:a23ff602d0797cea1d0506ce69b27523b07e70f6dda982ab8cf82402de839088"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ce07445050b537d2696022dafb115307abdffd2a5c106f029490f84501ef97"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:280ffe95f50eaaf655b3a1dc7ff1d9cf4777029dbbc3e63a74e65a056594abc3"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97acfcec592f7e9de8cadcdcda50a7134423ac8455c0166b28c9ff04d227b371"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7730c98a3010cd4f523465867ff95cd9d6430db46676ce79358f65ae39797b"}, + {file = "tokenizers-0.13.3-cp39-cp39-win32.whl", hash = "sha256:48625a108029cb1ddf42e17a81b5a3230ba6888a70c9dc14e81bc319e812652d"}, + {file = "tokenizers-0.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:bc0a6f1ba036e482db6453571c9e3e60ecd5489980ffd95d11dc9f960483d783"}, + {file = "tokenizers-0.13.3.tar.gz", hash = "sha256:2e546dbb68b623008a5442353137fbb0123d311a6d7ba52f2667c8862a75af2e"}, +] + +[package.extras] +dev = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] +docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] +testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tomlkit" +version = "0.12.1" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, + {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, +] + +[[package]] +name = "tqdm" +version = "4.66.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, + {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "twine" +version = "3.8.0" +description = "Collection of utilities for publishing packages on PyPI" +optional = false +python-versions = ">=3.6" +files = [ + {file = "twine-3.8.0-py3-none-any.whl", hash = "sha256:d0550fca9dc19f3d5e8eadfce0c227294df0a2a951251a4385797c8a6198b7c8"}, + {file = "twine-3.8.0.tar.gz", hash = "sha256:8efa52658e0ae770686a13b675569328f1fba9837e5de1867bfe5f46a9aefe19"}, +] + +[package.dependencies] +colorama = ">=0.4.3" +importlib-metadata = ">=3.6" +keyring = ">=15.1" +pkginfo = ">=1.8.1" +readme-renderer = ">=21.0" +requests = ">=2.20" +requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" +rfc3986 = ">=1.4.0" +tqdm = ">=4.14" +urllib3 = ">=1.26.0" + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + +[[package]] +name = "ujson" +version = "5.8.0" +description = "Ultra fast JSON encoder and decoder for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ujson-5.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4511560d75b15ecb367eef561554959b9d49b6ec3b8d5634212f9fed74a6df1"}, + {file = "ujson-5.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9399eaa5d1931a0ead49dce3ffacbea63f3177978588b956036bfe53cdf6af75"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4e7bb7eba0e1963f8b768f9c458ecb193e5bf6977090182e2b4f4408f35ac76"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40931d7c08c4ce99adc4b409ddb1bbb01635a950e81239c2382cfe24251b127a"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d53039d39de65360e924b511c7ca1a67b0975c34c015dd468fca492b11caa8f7"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bdf04c6af3852161be9613e458a1fb67327910391de8ffedb8332e60800147a2"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a70f776bda2e5072a086c02792c7863ba5833d565189e09fabbd04c8b4c3abba"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f26629ac531d712f93192c233a74888bc8b8212558bd7d04c349125f10199fcf"}, + {file = "ujson-5.8.0-cp310-cp310-win32.whl", hash = "sha256:7ecc33b107ae88405aebdb8d82c13d6944be2331ebb04399134c03171509371a"}, + {file = "ujson-5.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b27a8da7a080add559a3b73ec9ebd52e82cc4419f7c6fb7266e62439a055ed0"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:193349a998cd821483a25f5df30b44e8f495423840ee11b3b28df092ddfd0f7f"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ddeabbc78b2aed531f167d1e70387b151900bc856d61e9325fcdfefb2a51ad8"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ce24909a9c25062e60653073dd6d5e6ec9d6ad7ed6e0069450d5b673c854405"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27a2a3c7620ebe43641e926a1062bc04e92dbe90d3501687957d71b4bdddaec4"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b852bdf920fe9f84e2a2c210cc45f1b64f763b4f7d01468b33f7791698e455e"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:20768961a6a706170497129960762ded9c89fb1c10db2989c56956b162e2a8a3"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e0147d41e9fb5cd174207c4a2895c5e24813204499fd0839951d4c8784a23bf5"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e3673053b036fd161ae7a5a33358ccae6793ee89fd499000204676baafd7b3aa"}, + {file = "ujson-5.8.0-cp311-cp311-win32.whl", hash = "sha256:a89cf3cd8bf33a37600431b7024a7ccf499db25f9f0b332947fbc79043aad879"}, + {file = "ujson-5.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3659deec9ab9eb19e8646932bfe6fe22730757c4addbe9d7d5544e879dc1b721"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:102bf31c56f59538cccdfec45649780ae00657e86247c07edac434cb14d5388c"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:299a312c3e85edee1178cb6453645217ba23b4e3186412677fa48e9a7f986de6"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e385a7679b9088d7bc43a64811a7713cc7c33d032d020f757c54e7d41931ae"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad24ec130855d4430a682c7a60ca0bc158f8253ec81feed4073801f6b6cb681b"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16fde596d5e45bdf0d7de615346a102510ac8c405098e5595625015b0d4b5296"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6d230d870d1ce03df915e694dcfa3f4e8714369cce2346686dbe0bc8e3f135e7"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9571de0c53db5cbc265945e08f093f093af2c5a11e14772c72d8e37fceeedd08"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7cba16b26efe774c096a5e822e4f27097b7c81ed6fb5264a2b3f5fd8784bab30"}, + {file = "ujson-5.8.0-cp312-cp312-win32.whl", hash = "sha256:48c7d373ff22366eecfa36a52b9b55b0ee5bd44c2b50e16084aa88b9de038916"}, + {file = "ujson-5.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:5ac97b1e182d81cf395ded620528c59f4177eee024b4b39a50cdd7b720fdeec6"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2a64cc32bb4a436e5813b83f5aab0889927e5ea1788bf99b930fad853c5625cb"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e54578fa8838ddc722539a752adfce9372474114f8c127bb316db5392d942f8b"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9721cd112b5e4687cb4ade12a7b8af8b048d4991227ae8066d9c4b3a6642a582"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9707e5aacf63fb919f6237d6490c4e0244c7f8d3dc2a0f84d7dec5db7cb54c"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0be81bae295f65a6896b0c9030b55a106fb2dec69ef877253a87bc7c9c5308f7"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae7f4725c344bf437e9b881019c558416fe84ad9c6b67426416c131ad577df67"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9ab282d67ef3097105552bf151438b551cc4bedb3f24d80fada830f2e132aeb9"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94c7bd9880fa33fcf7f6d7f4cc032e2371adee3c5dba2922b918987141d1bf07"}, + {file = "ujson-5.8.0-cp38-cp38-win32.whl", hash = "sha256:bf5737dbcfe0fa0ac8fa599eceafae86b376492c8f1e4b84e3adf765f03fb564"}, + {file = "ujson-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:11da6bed916f9bfacf13f4fc6a9594abd62b2bb115acfb17a77b0f03bee4cfd5"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:69b3104a2603bab510497ceabc186ba40fef38ec731c0ccaa662e01ff94a985c"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9249fdefeb021e00b46025e77feed89cd91ffe9b3a49415239103fc1d5d9c29a"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2873d196725a8193f56dde527b322c4bc79ed97cd60f1d087826ac3290cf9207"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4dafa9010c366589f55afb0fd67084acd8added1a51251008f9ff2c3e44042"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a42baa647a50fa8bed53d4e242be61023bd37b93577f27f90ffe521ac9dc7a3"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f3554eaadffe416c6f543af442066afa6549edbc34fe6a7719818c3e72ebfe95"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fb87decf38cc82bcdea1d7511e73629e651bdec3a43ab40985167ab8449b769c"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:407d60eb942c318482bbfb1e66be093308bb11617d41c613e33b4ce5be789adc"}, + {file = "ujson-5.8.0-cp39-cp39-win32.whl", hash = "sha256:0fe1b7edaf560ca6ab023f81cbeaf9946a240876a993b8c5a21a1c539171d903"}, + {file = "ujson-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f9b63530a5392eb687baff3989d0fb5f45194ae5b1ca8276282fb647f8dcdb3"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:efeddf950fb15a832376c0c01d8d7713479fbeceaed1eaecb2665aa62c305aec"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d8283ac5d03e65f488530c43d6610134309085b71db4f675e9cf5dff96a8282"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb0142f6f10f57598655340a3b2c70ed4646cbe674191da195eb0985a9813b83"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d459aca895eb17eb463b00441986b021b9312c6c8cc1d06880925c7f51009c"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d524a8c15cfc863705991d70bbec998456a42c405c291d0f84a74ad7f35c5109"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d6f84a7a175c75beecde53a624881ff618e9433045a69fcfb5e154b73cdaa377"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b748797131ac7b29826d1524db1cc366d2722ab7afacc2ce1287cdafccddbf1f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e72ba76313d48a1a3a42e7dc9d1db32ea93fac782ad8dde6f8b13e35c229130"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f504117a39cb98abba4153bf0b46b4954cc5d62f6351a14660201500ba31fe7f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8c91b6f4bf23f274af9002b128d133b735141e867109487d17e344d38b87d94"}, + {file = "ujson-5.8.0.tar.gz", hash = "sha256:78e318def4ade898a461b3d92a79f9441e7e0e4d2ad5419abed4336d702c7425"}, +] + +[[package]] +name = "urllib3" +version = "1.26.16" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"}, + {file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "uvicorn" +version = "0.20.0" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.7" +files = [ + {file = "uvicorn-0.20.0-py3-none-any.whl", hash = "sha256:c3ed1598a5668208723f2bb49336f4509424ad198d6ab2615b7783db58d919fd"}, + {file = "uvicorn-0.20.0.tar.gz", hash = "sha256:a4e12017b940247f836bc90b72e725d7dfd0c8ed1c51eb365f5ba30d9f5127d8"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} +h11 = ">=0.8" +httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "uvloop" +version = "0.17.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = ">=3.7" +files = [ + {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718"}, + {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c"}, + {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d"}, + {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024"}, + {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa"}, + {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811"}, + {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c"}, + {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e"}, + {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539"}, + {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4"}, + {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05"}, + {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376"}, + {file = "uvloop-0.17.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b"}, + {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8"}, + {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62"}, + {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d"}, + {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667"}, + {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738"}, + {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20"}, + {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f"}, + {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595"}, + {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578"}, + {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474"}, + {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b"}, + {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c"}, + {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8"}, + {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c"}, + {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9"}, + {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded"}, + {file = "uvloop-0.17.0.tar.gz", hash = "sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1"}, +] + +[package.extras] +dev = ["Cython (>=0.29.32,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"] + +[[package]] +name = "validators" +version = "0.21.0" +description = "Python Data Validation for Humans™" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "validators-0.21.0-py3-none-any.whl", hash = "sha256:3470db6f2384c49727ee319afa2e97aec3f8fad736faa6067e0fd7f9eaf2c551"}, + {file = "validators-0.21.0.tar.gz", hash = "sha256:245b98ab778ed9352a7269c6a8f6c2a839bed5b2a7e3e60273ce399d247dd4b3"}, +] + +[[package]] +name = "watchfiles" +version = "0.19.0" +description = "Simple, modern and high performance file watching and code reload in python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "watchfiles-0.19.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:91633e64712df3051ca454ca7d1b976baf842d7a3640b87622b323c55f3345e7"}, + {file = "watchfiles-0.19.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b6577b8c6c8701ba8642ea9335a129836347894b666dd1ec2226830e263909d3"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18b28f6ad871b82df9542ff958d0c86bb0d8310bb09eb8e87d97318a3b5273af"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac19dc9cbc34052394dbe81e149411a62e71999c0a19e1e09ce537867f95ae0"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ea3397aecbc81c19ed7f025e051a7387feefdb789cf768ff994c1228182fda"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0376deac92377817e4fb8f347bf559b7d44ff556d9bc6f6208dd3f79f104aaf"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c75eff897786ee262c9f17a48886f4e98e6cfd335e011c591c305e5d083c056"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb5d45c4143c1dd60f98a16187fd123eda7248f84ef22244818c18d531a249d1"}, + {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:79c533ff593db861ae23436541f481ec896ee3da4e5db8962429b441bbaae16e"}, + {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3d7d267d27aceeeaa3de0dd161a0d64f0a282264d592e335fff7958cc0cbae7c"}, + {file = "watchfiles-0.19.0-cp37-abi3-win32.whl", hash = "sha256:176a9a7641ec2c97b24455135d58012a5be5c6217fc4d5fef0b2b9f75dbf5154"}, + {file = "watchfiles-0.19.0-cp37-abi3-win_amd64.whl", hash = "sha256:945be0baa3e2440151eb3718fd8846751e8b51d8de7b884c90b17d271d34cae8"}, + {file = "watchfiles-0.19.0-cp37-abi3-win_arm64.whl", hash = "sha256:0089c6dc24d436b373c3c57657bf4f9a453b13767150d17284fc6162b2791911"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cae3dde0b4b2078f31527acff6f486e23abed307ba4d3932466ba7cdd5ecec79"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f3920b1285a7d3ce898e303d84791b7bf40d57b7695ad549dc04e6a44c9f120"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9afd0d69429172c796164fd7fe8e821ade9be983f51c659a38da3faaaaac44dc"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68dce92b29575dda0f8d30c11742a8e2b9b8ec768ae414b54f7453f27bdf9545"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5569fc7f967429d4bc87e355cdfdcee6aabe4b620801e2cf5805ea245c06097c"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5471582658ea56fca122c0f0d0116a36807c63fefd6fdc92c71ca9a4491b6b48"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b538014a87f94d92f98f34d3e6d2635478e6be6423a9ea53e4dd96210065e193"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b44221764955b1e703f012c74015306fb7e79a00c15370785f309b1ed9aa8d"}, + {file = "watchfiles-0.19.0.tar.gz", hash = "sha256:d9b073073e048081e502b6c6b0b88714c026a1a4c890569238d04aca5f9ca74b"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + +[[package]] +name = "weaviate-client" +version = "3.22.1" +description = "A python native Weaviate client" +optional = false +python-versions = ">=3.8" +files = [ + {file = "weaviate-client-3.22.1.tar.gz", hash = "sha256:aff61bd3f5d74df20a62328443e3aa9c860d5330fdfb19c4d8ddc44cb604032f"}, + {file = "weaviate_client-3.22.1-py3-none-any.whl", hash = "sha256:01843a4899a227300e570409e77628e9d1b28476313f94943c37aee3f75112e1"}, +] + +[package.dependencies] +authlib = ">=1.1.0" +requests = ">=2.28.0,<=2.31.0" +tqdm = ">=4.59.0,<5.0.0" +validators = ">=0.18.2,<=0.21.0" + +[package.extras] +grpc = ["grpcio", "grpcio-tools"] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + +[[package]] +name = "websockets" +version = "10.4" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "websockets-10.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48"}, + {file = "websockets-10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab"}, + {file = "websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331"}, + {file = "websockets-10.4-cp310-cp310-win32.whl", hash = "sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a"}, + {file = "websockets-10.4-cp310-cp310-win_amd64.whl", hash = "sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089"}, + {file = "websockets-10.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4"}, + {file = "websockets-10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f"}, + {file = "websockets-10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9"}, + {file = "websockets-10.4-cp311-cp311-win32.whl", hash = "sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8"}, + {file = "websockets-10.4-cp311-cp311-win_amd64.whl", hash = "sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882"}, + {file = "websockets-10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c"}, + {file = "websockets-10.4-cp37-cp37m-win32.whl", hash = "sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038"}, + {file = "websockets-10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28"}, + {file = "websockets-10.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94"}, + {file = "websockets-10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63"}, + {file = "websockets-10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56"}, + {file = "websockets-10.4-cp38-cp38-win32.whl", hash = "sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a"}, + {file = "websockets-10.4-cp38-cp38-win_amd64.whl", hash = "sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6"}, + {file = "websockets-10.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f"}, + {file = "websockets-10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112"}, + {file = "websockets-10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b"}, + {file = "websockets-10.4-cp39-cp39-win32.whl", hash = "sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588"}, + {file = "websockets-10.4-cp39-cp39-win_amd64.whl", hash = "sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74"}, + {file = "websockets-10.4-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485"}, + {file = "websockets-10.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631"}, + {file = "websockets-10.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f"}, + {file = "websockets-10.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1"}, + {file = "websockets-10.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13"}, + {file = "websockets-10.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72"}, + {file = "websockets-10.4.tar.gz", hash = "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3"}, +] + +[[package]] +name = "wheel" +version = "0.41.2" +description = "A built-package format for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "wheel-0.41.2-py3-none-any.whl", hash = "sha256:75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8"}, + {file = "wheel-0.41.2.tar.gz", hash = "sha256:0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985"}, +] + +[package.extras] +test = ["pytest (>=6.0.0)", "setuptools (>=65)"] + +[[package]] +name = "win32-setctime" +version = "1.1.0" +description = "A small Python utility to set file creation time on Windows" +optional = false +python-versions = ">=3.5" +files = [ + {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, + {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, +] + +[package.extras] +dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] + +[[package]] +name = "xlsxwriter" +version = "3.1.2" +description = "A Python module for creating Excel XLSX files." +optional = false +python-versions = ">=3.6" +files = [ + {file = "XlsxWriter-3.1.2-py3-none-any.whl", hash = "sha256:331508ff39d610ecdaf979e458840bc1eab6e6a02cfd5d08f044f0f73636236f"}, + {file = "XlsxWriter-3.1.2.tar.gz", hash = "sha256:78751099a770273f1c98b8d6643351f68f98ae8e6acf9d09d37dc6798f8cd3de"}, +] + +[[package]] +name = "yarl" +version = "1.9.2" +description = "Yet another URL library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"}, + {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"}, + {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"}, + {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"}, + {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"}, + {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"}, + {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"}, + {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"}, + {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"}, + {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"}, + {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"}, + {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"}, + {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[[package]] +name = "zipp" +version = "3.16.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, + {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[[package]] +name = "zstandard" +version = "0.21.0" +description = "Zstandard bindings for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zstandard-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:649a67643257e3b2cff1c0a73130609679a5673bf389564bc6d4b164d822a7ce"}, + {file = "zstandard-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:144a4fe4be2e747bf9c646deab212666e39048faa4372abb6a250dab0f347a29"}, + {file = "zstandard-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b72060402524ab91e075881f6b6b3f37ab715663313030d0ce983da44960a86f"}, + {file = "zstandard-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8257752b97134477fb4e413529edaa04fc0457361d304c1319573de00ba796b1"}, + {file = "zstandard-0.21.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c053b7c4cbf71cc26808ed67ae955836232f7638444d709bfc302d3e499364fa"}, + {file = "zstandard-0.21.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2769730c13638e08b7a983b32cb67775650024632cd0476bf1ba0e6360f5ac7d"}, + {file = "zstandard-0.21.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7d3bc4de588b987f3934ca79140e226785d7b5e47e31756761e48644a45a6766"}, + {file = "zstandard-0.21.0-cp310-cp310-win32.whl", hash = "sha256:67829fdb82e7393ca68e543894cd0581a79243cc4ec74a836c305c70a5943f07"}, + {file = "zstandard-0.21.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6048a287f8d2d6e8bc67f6b42a766c61923641dd4022b7fd3f7439e17ba5a4d"}, + {file = "zstandard-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7f2afab2c727b6a3d466faee6974a7dad0d9991241c498e7317e5ccf53dbc766"}, + {file = "zstandard-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff0852da2abe86326b20abae912d0367878dd0854b8931897d44cfeb18985472"}, + {file = "zstandard-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12fa383e315b62630bd407477d750ec96a0f438447d0e6e496ab67b8b451d39"}, + {file = "zstandard-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1b9703fe2e6b6811886c44052647df7c37478af1b4a1a9078585806f42e5b15"}, + {file = "zstandard-0.21.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df28aa5c241f59a7ab524f8ad8bb75d9a23f7ed9d501b0fed6d40ec3064784e8"}, + {file = "zstandard-0.21.0-cp311-cp311-win32.whl", hash = "sha256:0aad6090ac164a9d237d096c8af241b8dcd015524ac6dbec1330092dba151657"}, + {file = "zstandard-0.21.0-cp311-cp311-win_amd64.whl", hash = "sha256:48b6233b5c4cacb7afb0ee6b4f91820afbb6c0e3ae0fa10abbc20000acdf4f11"}, + {file = "zstandard-0.21.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e7d560ce14fd209db6adacce8908244503a009c6c39eee0c10f138996cd66d3e"}, + {file = "zstandard-0.21.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e6e131a4df2eb6f64961cea6f979cdff22d6e0d5516feb0d09492c8fd36f3bc"}, + {file = "zstandard-0.21.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1e0c62a67ff425927898cf43da2cf6b852289ebcc2054514ea9bf121bec10a5"}, + {file = "zstandard-0.21.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1545fb9cb93e043351d0cb2ee73fa0ab32e61298968667bb924aac166278c3fc"}, + {file = "zstandard-0.21.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe6c821eb6870f81d73bf10e5deed80edcac1e63fbc40610e61f340723fd5f7c"}, + {file = "zstandard-0.21.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ddb086ea3b915e50f6604be93f4f64f168d3fc3cef3585bb9a375d5834392d4f"}, + {file = "zstandard-0.21.0-cp37-cp37m-win32.whl", hash = "sha256:57ac078ad7333c9db7a74804684099c4c77f98971c151cee18d17a12649bc25c"}, + {file = "zstandard-0.21.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1243b01fb7926a5a0417120c57d4c28b25a0200284af0525fddba812d575f605"}, + {file = "zstandard-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea68b1ba4f9678ac3d3e370d96442a6332d431e5050223626bdce748692226ea"}, + {file = "zstandard-0.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8070c1cdb4587a8aa038638acda3bd97c43c59e1e31705f2766d5576b329e97c"}, + {file = "zstandard-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4af612c96599b17e4930fe58bffd6514e6c25509d120f4eae6031b7595912f85"}, + {file = "zstandard-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff891e37b167bc477f35562cda1248acc115dbafbea4f3af54ec70821090965"}, + {file = "zstandard-0.21.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9fec02ce2b38e8b2e86079ff0b912445495e8ab0b137f9c0505f88ad0d61296"}, + {file = "zstandard-0.21.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bdbe350691dec3078b187b8304e6a9c4d9db3eb2d50ab5b1d748533e746d099"}, + {file = "zstandard-0.21.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b69cccd06a4a0a1d9fb3ec9a97600055cf03030ed7048d4bcb88c574f7895773"}, + {file = "zstandard-0.21.0-cp38-cp38-win32.whl", hash = "sha256:9980489f066a391c5572bc7dc471e903fb134e0b0001ea9b1d3eff85af0a6f1b"}, + {file = "zstandard-0.21.0-cp38-cp38-win_amd64.whl", hash = "sha256:0e1e94a9d9e35dc04bf90055e914077c80b1e0c15454cc5419e82529d3e70728"}, + {file = "zstandard-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d2d61675b2a73edcef5e327e38eb62bdfc89009960f0e3991eae5cc3d54718de"}, + {file = "zstandard-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25fbfef672ad798afab12e8fd204d122fca3bc8e2dcb0a2ba73bf0a0ac0f5f07"}, + {file = "zstandard-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62957069a7c2626ae80023998757e27bd28d933b165c487ab6f83ad3337f773d"}, + {file = "zstandard-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e10ed461e4807471075d4b7a2af51f5234c8f1e2a0c1d37d5ca49aaaad49e8"}, + {file = "zstandard-0.21.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9cff89a036c639a6a9299bf19e16bfb9ac7def9a7634c52c257166db09d950e7"}, + {file = "zstandard-0.21.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52b2b5e3e7670bd25835e0e0730a236f2b0df87672d99d3bf4bf87248aa659fb"}, + {file = "zstandard-0.21.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b1367da0dde8ae5040ef0413fb57b5baeac39d8931c70536d5f013b11d3fc3a5"}, + {file = "zstandard-0.21.0-cp39-cp39-win32.whl", hash = "sha256:db62cbe7a965e68ad2217a056107cc43d41764c66c895be05cf9c8b19578ce9c"}, + {file = "zstandard-0.21.0-cp39-cp39-win_amd64.whl", hash = "sha256:a8d200617d5c876221304b0e3fe43307adde291b4a897e7b0617a61611dfff6a"}, + {file = "zstandard-0.21.0.tar.gz", hash = "sha256:f08e3a10d01a247877e4cb61a82a319ea746c356a3786558bed2481e6c405546"}, +] + +[package.dependencies] +cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""} + +[package.extras] +cffi = ["cffi (>=1.11)"] + +[extras] +postgresql = ["psycopg2cffi"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "9213703fd449560f1d0a019f0204e5236353f6556b5da1dcb76d9f6de9f73ad0" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..2f2404176 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,70 @@ +[tool.poetry] +name = "chatgpt-retrieval-plugin" +version = "0.1.0" +description = "" +authors = ["isafulf "] +readme = "README.md" +packages = [ + {include = "server"}, + {include = "kdbai_client", from="/home/cposner/.local/lib/python3.10/site-packages/"}, +] + +[[tool.poetry.source]] +name = "azure-sdk-dev" +url = "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" +secondary = true + +[tool.poetry.dependencies] +python = "^3.10" +fastapi = "^0.92.0" +uvicorn = "^0.20.0" +openai = "^0.27.5" +python-dotenv = "^0.21.1" +pydantic = "^1.10.5" +tenacity = "^8.2.1" +tiktoken = "^0.2.0" +numpy = "^1.24.2" +docx2txt = "^0.8" +PyPDF2 = "^3.0.1" +python-pptx = "^0.6.21" +python-multipart = "^0.0.6" +arrow = "^1.2.3" +chromadb = "^0.3.25" +pinecone-client = "^2.1.0" +weaviate-client = "^3.12.0" +#pymilvus = "^2.2.2" +qdrant-client = {version = "^1.0.4", python = "<3.12"} +redis = "4.5.4" +supabase = "^1.0.2" +psycopg2 = "^2.9.5" +llama-index = "0.5.4" +azure-identity = "^1.12.0" +azure-search-documents = {version = "11.4.0a20230509004", source = "azure-sdk-dev"} +pgvector = "^0.1.7" +psycopg2cffi = {version = "^2.9.0", optional = true} +loguru = "^0.7.0" +elasticsearch = "8.8.2" +pykx="^1.6.3" + +[tool.poetry.scripts] +start = "server.main:start" +dev = "local_server.main:start" + +[tool.poetry.extras] +postgresql = ["psycopg2cffi"] + +[tool.poetry.group.dev.dependencies] +httpx = "^0.23.3" +pytest = "^7.2.1" +pytest-cov = "^4.0.0" +pytest-asyncio = "^0.20.3" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +pythonpath = [ + "." +] +asyncio_mode="auto" diff --git a/scripts/process_json/README.md b/scripts/process_json/README.md new file mode 100644 index 000000000..fe738c8a3 --- /dev/null +++ b/scripts/process_json/README.md @@ -0,0 +1,24 @@ +## Process a JSON File + +This script is a utility to process a file dump of documents in a JSON format and store them in the vector database with some metadata. It can also optionally screen the documents for personally identifiable information (PII) using a language model, and skip them if detected. Additionally, the script can extract metadata from the document using a language model. You can customize the PII detection function in [`services/pii_detection`](../../services/pii_detection.py) and the metadata extraction function in [`services/extract_metadata`](../../services/extract_metadata.py) for your use case. + +## Usage + +To run this script from the terminal, navigate to this folder and use the following command: + +``` +python process_json.py --filepath path/to/file_dump.json --custom_metadata '{"source": "file"}' --screen_for_pii True --extract_metadata True +``` + +where: + +- `path/to/file_dump.json` is the name or path to the file dump to be processed. The format of this JSON file should be a list of JSON objects, where each object represents a document. The JSON object should have a subset of the following fields: `id`, `text`, `source`, `source_id`, `url`, `created_at`, and `author`. The `text` field is required, while the rest are optional and will be used to populate the metadata of the document. If the `id` field is not specified, a random UUID will be generated for the document. +- `--custom_metadata` is an optional JSON string of key-value pairs to update the metadata of the documents. For example, `{"source": "file"}` will add a `source` field with the value `file` to the metadata of each document. The default value is an empty JSON object (`{}`). +- `--screen_for_pii` is an optional boolean flag to indicate whether to use the PII detection function or not. If set to `True`, the script will use the `screen_text_for_pii` function from the [`services/pii_detection`](../../services/pii_detection.py) module to check if the document text contains any PII using a language model. If PII is detected, the script will print a warning and skip the document. The default value is `False`. +- `--extract_metadata` is an optional boolean flag to indicate whether to try to extract metadata from the document using a language model. If set to `True`, the script will use the `extract_metadata_from_document` function from the [`services/extract_metadata`](../../services/extract_metadata.py) module to extract metadata from the document text and update the metadata object accordingly. The default value is`False`. + +The script will load the JSON file as a list of dictionaries, iterate over the data, create document objects, and batch upsert them into the database. It will also print some progress messages and error messages if any, as well as the number and content of the skipped items due to errors or PII detection. + +You can use `python process_json.py -h` to get a summary of the options and their descriptions. + +Test the script with the example file, [example.json](example.json). diff --git a/scripts/process_json/example.json b/scripts/process_json/example.json new file mode 100644 index 000000000..dc8f12bc1 --- /dev/null +++ b/scripts/process_json/example.json @@ -0,0 +1,25 @@ +[ + { + "id": "123", + "text": "This is a document about something", + "source": "file", + "source_id": "https://example.com/doc1", + "url": "https://example.com/doc1", + "created_at": "2021-01-01T12:00:00Z", + "author": "Alice" + }, + { + "text": "This is another document about something else", + "source": "file", + "source_id": "doc2.txt", + "author": "Bob" + }, + { + "id": "456", + "text": "This is Alice's phone number: 123-456-7890", + "source": "email", + "source_id": "567", + "created_at": "2021-01-02T13:00:00Z", + "author": "Alice" + } +] \ No newline at end of file diff --git a/scripts/process_json/process_json.py b/scripts/process_json/process_json.py new file mode 100644 index 000000000..8b9624cbb --- /dev/null +++ b/scripts/process_json/process_json.py @@ -0,0 +1,147 @@ +import uuid +import json +import argparse +import asyncio + +from loguru import logger +from models.models import Document, DocumentMetadata +from datastore.datastore import DataStore +from datastore.factory import get_datastore +from services.extract_metadata import extract_metadata_from_document +from services.pii_detection import screen_text_for_pii + +DOCUMENT_UPSERT_BATCH_SIZE = 50 + + +async def process_json_dump( + filepath: str, + datastore: DataStore, + custom_metadata: dict, + screen_for_pii: bool, + extract_metadata: bool, +): + # load the json file as a list of dictionaries + with open(filepath) as json_file: + data = json.load(json_file) + + documents = [] + skipped_items = [] + # iterate over the data and create document objects + for item in data: + if len(documents) % 20 == 0: + logger.info(f"Processed {len(documents)} documents") + + try: + # get the id, text, source, source_id, url, created_at and author from the item + # use default values if not specified + id = item.get("id", None) + text = item.get("text", None) + source = item.get("source", None) + source_id = item.get("source_id", None) + url = item.get("url", None) + created_at = item.get("created_at", None) + author = item.get("author", None) + + if not text: + logger.info("No document text, skipping...") + continue + + # create a metadata object with the source, source_id, url, created_at and author + metadata = DocumentMetadata( + source=source, + source_id=source_id, + url=url, + created_at=created_at, + author=author, + ) + logger.info("metadata: ", str(metadata)) + + # update metadata with custom values + for key, value in custom_metadata.items(): + if hasattr(metadata, key): + setattr(metadata, key, value) + + # screen for pii if requested + if screen_for_pii: + pii_detected = screen_text_for_pii(text) + # if pii detected, print a warning and skip the document + if pii_detected: + logger.info("PII detected in document, skipping") + skipped_items.append(item) # add the skipped item to the list + continue + + # extract metadata if requested + if extract_metadata: + # extract metadata from the document text + extracted_metadata = extract_metadata_from_document( + f"Text: {text}; Metadata: {str(metadata)}" + ) + # get a Metadata object from the extracted metadata + metadata = DocumentMetadata(**extracted_metadata) + + # create a document object with the id or a random id, text and metadata + document = Document( + id=id or str(uuid.uuid4()), + text=text, + metadata=metadata, + ) + documents.append(document) + except Exception as e: + # log the error and continue with the next item + logger.error(f"Error processing {item}: {e}") + skipped_items.append(item) # add the skipped item to the list + + # do this in batches, the upsert method already batches documents but this allows + # us to add more descriptive logging + for i in range(0, len(documents), DOCUMENT_UPSERT_BATCH_SIZE): + # Get the text of the chunks in the current batch + batch_documents = documents[i : i + DOCUMENT_UPSERT_BATCH_SIZE] + logger.info(f"Upserting batch of {len(batch_documents)} documents, batch {i}") + logger.info("documents: ", documents) + await datastore.upsert(batch_documents) + + # print the skipped items + logger.info(f"Skipped {len(skipped_items)} items due to errors or PII detection") + for item in skipped_items: + logger.info(item) + + +async def main(): + # parse the command-line arguments + parser = argparse.ArgumentParser() + parser.add_argument("--filepath", required=True, help="The path to the json dump") + parser.add_argument( + "--custom_metadata", + default="{}", + help="A JSON string of key-value pairs to update the metadata of the documents", + ) + parser.add_argument( + "--screen_for_pii", + default=False, + type=bool, + help="A boolean flag to indicate whether to try the PII detection function (using a language model)", + ) + parser.add_argument( + "--extract_metadata", + default=False, + type=bool, + help="A boolean flag to indicate whether to try to extract metadata from the document (using a language model)", + ) + args = parser.parse_args() + + # get the arguments + filepath = args.filepath + custom_metadata = json.loads(args.custom_metadata) + screen_for_pii = args.screen_for_pii + extract_metadata = args.extract_metadata + + # initialize the db instance once as a global variable + datastore = await get_datastore() + # process the json dump + await process_json_dump( + filepath, datastore, custom_metadata, screen_for_pii, extract_metadata + ) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/scripts/process_jsonl/README.md b/scripts/process_jsonl/README.md new file mode 100644 index 000000000..df4073978 --- /dev/null +++ b/scripts/process_jsonl/README.md @@ -0,0 +1,24 @@ +## Process a JSONL File + +This script is a utility to process a file dump of documents in a JSONL format and store them in the vector database with some metadata. It can also optionally screen the documents for personally identifiable information (PII) using a language model, and skip them if detected. Additionally, the script can extract metadata from the document using a language model. You can customize the PII detection function in [`services/pii_detection`](../../services/pii_detection.py) and the metadata extraction function in [`services/extract_metadata`](../../services/extract_metadata.py) for your use case. + +## Usage + +To run this script from the terminal, navigate to this folder and use the following command: + +``` +python process_jsonl.py --filepath path/to/file_dump.jsonl --custom_metadata '{"source": "email"}' --screen_for_pii True --extract_metadata True +``` + +where: + +- `path/to/file_dump.jsonl` is the name or path to the file dump to be processed. The format of this JSONL file should be a newline-delimited JSON file, where each line is a valid JSON object representing a document. The JSON object should have a subset of the following fields: `id`, `text`, `source`, `source_id`, `url`, `created_at`, and `author`. The `text` field is required, while the rest are optional and will be used to populate the metadata of the document. If the `id` field is not specified, a random UUID will be generated for the document. +- `--custom_metadata` is an optional JSON string of key-value pairs to update the metadata of the documents. For example, `{"source": "file"}` will add a `source` field with the value `file` to the metadata of each document. The default value is an empty JSON object (`{}`). +- `--screen_for_pii` is an optional boolean flag to indicate whether to use the PII detection function or not. If set to `True`, the script will use the `screen_text_for_pii` function from the [`services/pii_detection`](../../services/pii_detection.py) module to check if the document text contains any PII using a language model. If PII is detected, the script will print a warning and skip the document. The default value is `False`. +- `--extract_metadata` is an optional boolean flag to indicate whether to try to extract metadata from the document using a language model. If set to `True`, the script will use the `extract_metadata_from_document` function from the [`services/extract_metadata`](../../services/extract_metadata.py) module to extract metadata from the document text and update the metadata object accordingly. The default value is`False`. + +The script will open the JSONL file as a generator of dictionaries, iterate over the data, create document objects, and batch upsert them into the database. It will also print some progress messages and error messages if any, as well as the number and content of the skipped items due to errors, PII detection, or metadata extraction issues. + +You can use `python process_jsonl.py -h` to get a summary of the options and their descriptions. + +Test the script with the example file, [example.jsonl](example.jsonl). diff --git a/scripts/process_jsonl/example.jsonl b/scripts/process_jsonl/example.jsonl new file mode 100644 index 000000000..6335bc4cd --- /dev/null +++ b/scripts/process_jsonl/example.jsonl @@ -0,0 +1,6 @@ +{"id": "4", "text": "This document only has an ID and text. The other fields are missing."} +{"text": "This document has no ID, but it has text and a source.", "source": "email"} +{"id": "6", "text": "This document has an ID, text, and author, but no source information.", "author": "John Doe"} +{"text": "This document has text, a source, and a URL, but no ID or author.", "source": "file", "url": "https://example.com/file/2"} +{"id": "8", "text": "This document has an ID, text, source, and created_at timestamp, but no author or URL.", "source": "chat", "created_at": "2022-01-04T00:00:00"} +{"id": "9", "text": "This document contains PII. John Smith's email address is john.smith@example.com and his phone number is +1 (555) 123-4567.", "source": "email", "source_id": "email_2", "url": "https://example.com/email/2", "created_at": "2022-01-05T00:00:00", "author": "John Smith"} \ No newline at end of file diff --git a/scripts/process_jsonl/process_jsonl.py b/scripts/process_jsonl/process_jsonl.py new file mode 100644 index 000000000..463871b96 --- /dev/null +++ b/scripts/process_jsonl/process_jsonl.py @@ -0,0 +1,145 @@ +import uuid +import json +import argparse +import asyncio + +from loguru import logger +from models.models import Document, DocumentMetadata +from datastore.datastore import DataStore +from datastore.factory import get_datastore +from services.extract_metadata import extract_metadata_from_document +from services.pii_detection import screen_text_for_pii + +DOCUMENT_UPSERT_BATCH_SIZE = 50 + + +async def process_jsonl_dump( + filepath: str, + datastore: DataStore, + custom_metadata: dict, + screen_for_pii: bool, + extract_metadata: bool, +): + # open the jsonl file as a generator of dictionaries + with open(filepath) as jsonl_file: + data = [json.loads(line) for line in jsonl_file] + + documents = [] + skipped_items = [] + # iterate over the data and create document objects + for item in data: + if len(documents) % 20 == 0: + logger.info(f"Processed {len(documents)} documents") + + try: + # get the id, text, source, source_id, url, created_at and author from the item + # use default values if not specified + id = item.get("id", None) + text = item.get("text", None) + source = item.get("source", None) + source_id = item.get("source_id", None) + url = item.get("url", None) + created_at = item.get("created_at", None) + author = item.get("author", None) + + if not text: + logger.info("No document text, skipping...") + continue + + # create a metadata object with the source, source_id, url, created_at and author + metadata = DocumentMetadata( + source=source, + source_id=source_id, + url=url, + created_at=created_at, + author=author, + ) + + # update metadata with custom values + for key, value in custom_metadata.items(): + if hasattr(metadata, key): + setattr(metadata, key, value) + + # screen for pii if requested + if screen_for_pii: + pii_detected = screen_text_for_pii(text) + # if pii detected, print a warning and skip the document + if pii_detected: + logger.info("PII detected in document, skipping") + skipped_items.append(item) # add the skipped item to the list + continue + + # extract metadata if requested + if extract_metadata: + # extract metadata from the document text + extracted_metadata = extract_metadata_from_document( + f"Text: {text}; Metadata: {str(metadata)}" + ) + # get a Metadata object from the extracted metadata + metadata = DocumentMetadata(**extracted_metadata) + + # create a document object with the id, text and metadata + document = Document( + id=id, + text=text, + metadata=metadata, + ) + documents.append(document) + except Exception as e: + # log the error and continue with the next item + logger.error(f"Error processing {item}: {e}") + skipped_items.append(item) # add the skipped item to the list + + # do this in batches, the upsert method already batches documents but this allows + # us to add more descriptive logging + for i in range(0, len(documents), DOCUMENT_UPSERT_BATCH_SIZE): + # Get the text of the chunks in the current batch + batch_documents = documents[i : i + DOCUMENT_UPSERT_BATCH_SIZE] + logger.info(f"Upserting batch of {len(batch_documents)} documents, batch {i}") + await datastore.upsert(batch_documents) + + # print the skipped items + logger.info(f"Skipped {len(skipped_items)} items due to errors or PII detection") + for item in skipped_items: + logger.info(item) + + +async def main(): + # parse the command-line arguments + parser = argparse.ArgumentParser() + parser.add_argument("--filepath", required=True, help="The path to the jsonl dump") + parser.add_argument( + "--custom_metadata", + default="{}", + help="A JSON string of key-value pairs to update the metadata of the documents", + ) + parser.add_argument( + "--screen_for_pii", + default=False, + type=bool, + help="A boolean flag to indicate whether to try the PII detection function (using a language model)", + ) + parser.add_argument( + "--extract_metadata", + default=False, + type=bool, + help="A boolean flag to indicate whether to try to extract metadata from the document (using a language model)", + ) + args = parser.parse_args() + + # get the arguments + filepath = args.filepath + custom_metadata = json.loads(args.custom_metadata) + screen_for_pii = args.screen_for_pii + extract_metadata = args.extract_metadata + + # initialize the db instance once as a global variable + datastore = await get_datastore() + # process the jsonl dump + await process_jsonl_dump( + filepath, datastore, custom_metadata, screen_for_pii, extract_metadata + ) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/scripts/process_zip/README.md b/scripts/process_zip/README.md new file mode 100644 index 000000000..181a733aa --- /dev/null +++ b/scripts/process_zip/README.md @@ -0,0 +1,24 @@ +## Process a ZIP File + +This script is a utility to process a file dump of documents in a zip file and store them in the vector database with some metadata. It can also optionally screen the documents for personally identifiable information (PII) using a language model, and skip them if detected. Additionally, the script can extract metadata from the document using a language model. You can customize the PII detection function in [`services/pii_detection`](../../services/pii_detection.py) and the metadata extraction function in [`services/extract_metadata`](../../services/extract_metadata.py) for your use case. + +## Usage + +To run this script from the terminal, navigate to this folder and use the following command: + +``` +python process_zip.py --filepath path/to/file_dump.zip --custom_metadata '{"source": "email"}' --screen_for_pii True --extract_metadata True +``` + +where: + +- `path/to/file_dump.zip` is the name or path to the file dump to be processed. The format of this zip file should be a zip file containing of docx, pdf, txt, md and pptx files (any internal folder structure is acceptable). +- `--custom_metadata` is an optional JSON string of key-value pairs to update the metadata of the documents. For example, `{"source": "file"}` will add a `source` field with the value `file` to the metadata of each document. The default value is an empty JSON object (`{}`). +- `--screen_for_pii` is an optional boolean flag to indicate whether to use the PII detection function or not. If set to `True`, the script will use the `screen_text_for_pii` function from the [`services/pii_detection`](../../services/pii_detection.py) module to check if the document text contains any PII using a language model. If PII is detected, the script will print a warning and skip the document. The default value is `False`. +- `--extract_metadata` is an optional boolean flag to indicate whether to try to extract metadata from the document using a language model. If set to `True`, the script will use the `extract_metadata_from_document` function from the [`services/extract_metadata`](../../services/extract_metadata.py) module to extract metadata from the document text and update the metadata object accordingly. The default value is`False`. + +The script will extract the files from the zip file into a temporary directory named `dump`, process each file and store the document text and metadata in the database, and then delete the temporary directory and its contents. It will also print some progress messages and error messages if any. + +You can use `python process_zip.py -h` to get a summary of the options and their descriptions. + +Test the script with the example file, [example.zip](example.zip). diff --git a/scripts/process_zip/example.zip b/scripts/process_zip/example.zip new file mode 100644 index 0000000000000000000000000000000000000000..d35d27639087c73a9eb5148aa507f35b862d44b5 GIT binary patch literal 53296 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 cf9LZLv`qN38s)Vh5(sN?u+JHyOyuHAL{N3 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 V4x8Nkl+v73JCLEpOhAH#0RZD`Bsc&7 literal 0 HcmV?d00001 diff --git a/services/__pycache__/chunks.cpython-310.pyc b/services/__pycache__/chunks.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42a3b669e7910d02064bb4960b2bc3c3963eea39 GIT binary patch literal 4338 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 ZqwaeD){B`IRUu#cu{JTP7CEF3!#}@K@s|Jq literal 0 HcmV?d00001 diff --git a/services/__pycache__/file.cpython-310.pyc b/services/__pycache__/file.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..224935a9af15ec3276a850d07c29a616032599e8 GIT binary patch literal 3153 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 List[str]: + """ + Split a text into chunks of ~CHUNK_SIZE tokens, based on punctuation and newline boundaries. + + Args: + text: The text to split into chunks. + chunk_token_size: The target size of each chunk in tokens, or None to use the default CHUNK_SIZE. + + Returns: + A list of text chunks, each of which is a string of ~CHUNK_SIZE tokens. + """ + # Return an empty list if the text is empty or whitespace + if not text or text.isspace(): + return [] + + # Tokenize the text + tokens = tokenizer.encode(text, disallowed_special=()) + + # Initialize an empty list of chunks + chunks = [] + + # Use the provided chunk token size or the default one + chunk_size = chunk_token_size or CHUNK_SIZE + + # Initialize a counter for the number of chunks + num_chunks = 0 + + # Loop until all tokens are consumed + while tokens and num_chunks < MAX_NUM_CHUNKS: + # Take the first chunk_size tokens as a chunk + chunk = tokens[:chunk_size] + + # Decode the chunk into text + chunk_text = tokenizer.decode(chunk) + + # Skip the chunk if it is empty or whitespace + if not chunk_text or chunk_text.isspace(): + # Remove the tokens corresponding to the chunk text from the remaining tokens + tokens = tokens[len(chunk) :] + # Continue to the next iteration of the loop + continue + + # Find the last period or punctuation mark in the chunk + last_punctuation = max( + chunk_text.rfind("."), + chunk_text.rfind("?"), + chunk_text.rfind("!"), + chunk_text.rfind("\n"), + ) + + # If there is a punctuation mark, and the last punctuation index is before MIN_CHUNK_SIZE_CHARS + if last_punctuation != -1 and last_punctuation > MIN_CHUNK_SIZE_CHARS: + # Truncate the chunk text at the punctuation mark + chunk_text = chunk_text[: last_punctuation + 1] + + # Remove any newline characters and strip any leading or trailing whitespace + chunk_text_to_append = chunk_text.replace("\n", " ").strip() + + if len(chunk_text_to_append) > MIN_CHUNK_LENGTH_TO_EMBED: + # Append the chunk text to the list of chunks + chunks.append(chunk_text_to_append) + + # Remove the tokens corresponding to the chunk text from the remaining tokens + tokens = tokens[len(tokenizer.encode(chunk_text, disallowed_special=())) :] + + # Increment the number of chunks + num_chunks += 1 + + # Handle the remaining tokens + if tokens: + remaining_text = tokenizer.decode(tokens).replace("\n", " ").strip() + if len(remaining_text) > MIN_CHUNK_LENGTH_TO_EMBED: + chunks.append(remaining_text) + + return chunks + + +def create_document_chunks( + doc: Document, chunk_token_size: Optional[int] +) -> Tuple[List[DocumentChunk], str]: + """ + Create a list of document chunks from a document object and return the document id. + + Args: + doc: The document object to create chunks from. It should have a text attribute and optionally an id and a metadata attribute. + chunk_token_size: The target size of each chunk in tokens, or None to use the default CHUNK_SIZE. + + Returns: + A tuple of (doc_chunks, doc_id), where doc_chunks is a list of document chunks, each of which is a DocumentChunk object with an id, a document_id, a text, and a metadata attribute, + and doc_id is the id of the document object, generated if not provided. The id of each chunk is generated from the document id and a sequential number, and the metadata is copied from the document object. + """ + # Check if the document text is empty or whitespace + if not doc.text or doc.text.isspace(): + return [], doc.id or str(uuid.uuid4()) + + # Generate a document id if not provided + doc_id = doc.id or str(uuid.uuid4()) + + # Split the document text into chunks + text_chunks = get_text_chunks(doc.text, chunk_token_size) + + metadata = ( + DocumentChunkMetadata(**doc.metadata.__dict__) + if doc.metadata is not None + else DocumentChunkMetadata() + ) + + metadata.document_id = doc_id + + # Initialize an empty list of chunks for this document + doc_chunks = [] + + # Assign each chunk a sequential number and create a DocumentChunk object + for i, text_chunk in enumerate(text_chunks): + chunk_id = f"{doc_id}_{i}" + doc_chunk = DocumentChunk( + id=chunk_id, + text=text_chunk, + metadata=metadata, + ) + # Append the chunk object to the list of chunks for this document + doc_chunks.append(doc_chunk) + + # Return the list of chunks and the document id + return doc_chunks, doc_id + + +def get_document_chunks( + documents: List[Document], chunk_token_size: Optional[int] +) -> Dict[str, List[DocumentChunk]]: + """ + Convert a list of documents into a dictionary from document id to list of document chunks. + + Args: + documents: The list of documents to convert. + chunk_token_size: The target size of each chunk in tokens, or None to use the default CHUNK_SIZE. + + Returns: + A dictionary mapping each document id to a list of document chunks, each of which is a DocumentChunk object + with text, metadata, and embedding attributes. + """ + # Initialize an empty dictionary of lists of chunks + chunks: Dict[str, List[DocumentChunk]] = {} + + # Initialize an empty list of all chunks + all_chunks: List[DocumentChunk] = [] + + # Loop over each document and create chunks + for doc in documents: + doc_chunks, doc_id = create_document_chunks(doc, chunk_token_size) + + # Append the chunks for this document to the list of all chunks + all_chunks.extend(doc_chunks) + + # Add the list of chunks for this document to the dictionary with the document id as the key + chunks[doc_id] = doc_chunks + + # Check if there are no chunks + if not all_chunks: + return {} + + # Get all the embeddings for the document chunks in batches, using get_embeddings + embeddings: List[List[float]] = [] + for i in range(0, len(all_chunks), EMBEDDINGS_BATCH_SIZE): + # Get the text of the chunks in the current batch + batch_texts = [ + chunk.text for chunk in all_chunks[i : i + EMBEDDINGS_BATCH_SIZE] + ] + + # Get the embeddings for the batch texts + batch_embeddings = get_embeddings(batch_texts) + + # Append the batch embeddings to the embeddings list + embeddings.extend(batch_embeddings) + + # Update the document chunk objects with the embeddings + for i, chunk in enumerate(all_chunks): + # Assign the embedding from the embeddings list to the chunk object + chunk.embedding = embeddings[i] + + return chunks diff --git a/services/date.py b/services/date.py new file mode 100644 index 000000000..476c7aedb --- /dev/null +++ b/services/date.py @@ -0,0 +1,24 @@ +import arrow +from loguru import logger + + +def to_unix_timestamp(date_str: str) -> int: + """ + Convert a date string to a unix timestamp (seconds since epoch). + + Args: + date_str: The date string to convert. + + Returns: + The unix timestamp corresponding to the date string. + + If the date string cannot be parsed as a valid date format, returns the current unix timestamp and prints a warning. + """ + # Try to parse the date string using arrow, which supports many common date formats + try: + date_obj = arrow.get(date_str) + return int(date_obj.timestamp()) + except arrow.parser.ParserError: + # If the parsing fails, return the current unix timestamp and print a warning + logger.info(f"Invalid date format: {date_str}") + return int(arrow.now().timestamp()) diff --git a/services/extract_metadata.py b/services/extract_metadata.py new file mode 100644 index 000000000..8c8d4ae7e --- /dev/null +++ b/services/extract_metadata.py @@ -0,0 +1,43 @@ +from models.models import Source +from services.openai import get_chat_completion +import json +from typing import Dict +import os +from loguru import logger + +def extract_metadata_from_document(text: str) -> Dict[str, str]: + sources = Source.__members__.keys() + sources_string = ", ".join(sources) + # This prompt is just an example, change it to fit your use case + messages = [ + { + "role": "system", + "content": f""" + Given a document from a user, try to extract the following metadata: + - source: string, one of {sources_string} + - url: string or don't specify + - created_at: string or don't specify + - author: string or don't specify + + Respond with a JSON containing the extracted metadata in key value pairs. If you don't find a metadata field, don't specify it. + """, + }, + {"role": "user", "content": text}, + ] + + # NOTE: Azure Open AI requires deployment id + # Read environment variable - if not set - not used + completion = get_chat_completion( + messages, + "gpt-4", + os.environ.get("OPENAI_METADATA_EXTRACTIONMODEL_DEPLOYMENTID") + ) # TODO: change to your preferred model name + + logger.info(f"completion: {completion}") + + try: + metadata = json.loads(completion) + except: + metadata = {} + + return metadata diff --git a/services/file.py b/services/file.py new file mode 100644 index 000000000..136fc17c5 --- /dev/null +++ b/services/file.py @@ -0,0 +1,117 @@ +import os +from io import BufferedReader +from typing import Optional +from fastapi import UploadFile +import mimetypes +from PyPDF2 import PdfReader +import docx2txt +import csv +import pptx +from loguru import logger + +from models.models import Document, DocumentMetadata + + +async def get_document_from_file( + file: UploadFile, metadata: DocumentMetadata +) -> Document: + extracted_text = await extract_text_from_form_file(file) + + doc = Document(text=extracted_text, metadata=metadata) + + return doc + + +def extract_text_from_filepath(filepath: str, mimetype: Optional[str] = None) -> str: + """Return the text content of a file given its filepath.""" + + if mimetype is None: + # Get the mimetype of the file based on its extension + mimetype, _ = mimetypes.guess_type(filepath) + + if not mimetype: + if filepath.endswith(".md"): + mimetype = "text/markdown" + else: + raise Exception("Unsupported file type") + + try: + with open(filepath, "rb") as file: + extracted_text = extract_text_from_file(file, mimetype) + except Exception as e: + logger.error(e) + raise e + + return extracted_text + + +def extract_text_from_file(file: BufferedReader, mimetype: str) -> str: + if mimetype == "application/pdf": + # Extract text from pdf using PyPDF2 + reader = PdfReader(file) + extracted_text = " ".join([page.extract_text() for page in reader.pages]) + elif mimetype == "text/plain" or mimetype == "text/markdown": + # Read text from plain text file + extracted_text = file.read().decode("utf-8") + elif ( + mimetype + == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ): + # Extract text from docx using docx2txt + extracted_text = docx2txt.process(file) + elif mimetype == "text/csv": + # Extract text from csv using csv module + extracted_text = "" + decoded_buffer = (line.decode("utf-8") for line in file) + reader = csv.reader(decoded_buffer) + for row in reader: + extracted_text += " ".join(row) + "\n" + elif ( + mimetype + == "application/vnd.openxmlformats-officedocument.presentationml.presentation" + ): + # Extract text from pptx using python-pptx + extracted_text = "" + presentation = pptx.Presentation(file) + for slide in presentation.slides: + for shape in slide.shapes: + if shape.has_text_frame: + for paragraph in shape.text_frame.paragraphs: + for run in paragraph.runs: + extracted_text += run.text + " " + extracted_text += "\n" + else: + # Unsupported file type + raise ValueError("Unsupported file type: {}".format(mimetype)) + + return extracted_text + + +# Extract text from a file based on its mimetype +async def extract_text_from_form_file(file: UploadFile): + """Return the text content of a file.""" + # get the file body from the upload file object + mimetype = file.content_type + logger.info(f"mimetype: {mimetype}") + logger.info(f"file.file: {file.file}") + logger.info("file: ", file) + + file_stream = await file.read() + + temp_file_path = "/tmp/temp_file" + + # write the file to a temporary location + with open(temp_file_path, "wb") as f: + f.write(file_stream) + + try: + extracted_text = extract_text_from_filepath(temp_file_path, mimetype) + except Exception as e: + logger.error(e) + os.remove(temp_file_path) + raise e + + # remove file from temp location + os.remove(temp_file_path) + + return extracted_text diff --git a/services/openai.py b/services/openai.py new file mode 100644 index 000000000..ddc2855ee --- /dev/null +++ b/services/openai.py @@ -0,0 +1,77 @@ +from typing import List +import openai +import os +from loguru import logger + +from tenacity import retry, wait_random_exponential, stop_after_attempt + + +@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(3)) +def get_embeddings(texts: List[str]) -> List[List[float]]: + """ + Embed texts using OpenAI's ada model. + + Args: + texts: The list of texts to embed. + + Returns: + A list of embeddings, each of which is a list of floats. + + Raises: + Exception: If the OpenAI API call fails. + """ + # Call the OpenAI API to get the embeddings + # NOTE: Azure Open AI requires deployment id + deployment = os.environ.get("OPENAI_EMBEDDINGMODEL_DEPLOYMENTID") + + response = {} + if deployment == None: + response = openai.Embedding.create(input=texts, model="text-embedding-ada-002") + else: + response = openai.Embedding.create(input=texts, deployment_id=deployment) + + # Extract the embedding data from the response + data = response["data"] # type: ignore + + # Return the embeddings as a list of lists of floats + return [result["embedding"] for result in data] + + +@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(3)) +def get_chat_completion( + messages, + model="gpt-3.5-turbo", # use "gpt-4" for better results + deployment_id = None +): + """ + Generate a chat completion using OpenAI's chat completion API. + + Args: + messages: The list of messages in the chat history. + model: The name of the model to use for the completion. Default is gpt-3.5-turbo, which is a fast, cheap and versatile model. Use gpt-4 for higher quality but slower results. + + Returns: + A string containing the chat completion. + + Raises: + Exception: If the OpenAI API call fails. + """ + # call the OpenAI chat completion API with the given messages + # Note: Azure Open AI requires deployment id + response = {} + if deployment_id == None: + response = openai.ChatCompletion.create( + model=model, + messages=messages, + ) + else: + response = openai.ChatCompletion.create( + deployment_id = deployment_id, + messages=messages, + ) + + + choices = response["choices"] # type: ignore + completion = choices[0].message.content.strip() + logger.info(f"Completion: {completion}") + return completion diff --git a/services/pii_detection.py b/services/pii_detection.py new file mode 100644 index 000000000..7d9015173 --- /dev/null +++ b/services/pii_detection.py @@ -0,0 +1,32 @@ +import os +from services.openai import get_chat_completion + + +def screen_text_for_pii(text: str) -> bool: + # This prompt is just an example, change it to fit your use case + messages = [ + { + "role": "system", + "content": f""" + You can only respond with the word "True" or "False", where your answer indicates whether the text in the user's message contains PII. + Do not explain your answer, and do not use punctuation. + Your task is to identify whether the text extracted from your company files + contains sensitive PII information that should not be shared with the broader company. Here are some things to look out for: + - An email address that identifies a specific person in either the local-part or the domain + - The postal address of a private residence (must include at least a street name) + - The postal address of a public place (must include either a street name or business name) + - Notes about hiring decisions with mentioned names of candidates. The user will send a document for you to analyze. + """, + }, + {"role": "user", "content": text}, + ] + + completion = get_chat_completion( + messages, + deployment_id=os.environ.get("OPENAI_COMPLETIONMODEL_DEPLOYMENTID") + ) + + if completion.startswith("True"): + return True + + return False diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/datastore/providers/analyticdb/test_analyticdb_datastore.py b/tests/datastore/providers/analyticdb/test_analyticdb_datastore.py new file mode 100644 index 000000000..9a79b9f43 --- /dev/null +++ b/tests/datastore/providers/analyticdb/test_analyticdb_datastore.py @@ -0,0 +1,323 @@ +import pytest +from models.models import ( + DocumentChunkMetadata, + DocumentMetadataFilter, + DocumentChunk, + QueryWithEmbedding, + Source, +) +from datastore.providers.analyticdb_datastore import ( + OUTPUT_DIM, + AnalyticDBDataStore, +) + + +@pytest.fixture +def analyticdb_datastore(): + return AnalyticDBDataStore() + + +@pytest.fixture +def document_chunk_one(): + doc_id = "zerp" + doc_chunks = [] + + ids = ["abc_123", "def_456", "ghi_789"] + texts = [ + "lorem ipsum dolor sit amet", + "consectetur adipiscing elit", + "sed do eiusmod tempor incididunt", + ] + sources = [Source.email, Source.file, Source.chat] + source_ids = ["foo", "bar", "baz"] + urls = ["foo.com", "bar.net", "baz.org"] + created_ats = [ + "1929-10-28T09:30:00-05:00", + "2009-01-03T16:39:57-08:00", + "2021-01-21T10:00:00-02:00", + ] + authors = ["Max Mustermann", "John Doe", "Jane Doe"] + embeddings = [[x] * OUTPUT_DIM for x in range(3)] + + for i in range(3): + chunk = DocumentChunk( + id=ids[i], + text=texts[i], + metadata=DocumentChunkMetadata( + document_id=doc_id, + source=sources[i], + source_id=source_ids[i], + url=urls[i], + created_at=created_ats[i], + author=authors[i], + ), + embedding=embeddings[i], # type: ignore + ) + + doc_chunks.append(chunk) + + return {doc_id: doc_chunks} + + +@pytest.fixture +def document_chunk_two(): + doc_id_1 = "zerp" + doc_chunks_1 = [] + + ids = ["abc_123", "def_456", "ghi_789"] + texts = [ + "1lorem ipsum dolor sit amet", + "2consectetur adipiscing elit", + "3sed do eiusmod tempor incididunt", + ] + sources = [Source.email, Source.file, Source.chat] + source_ids = ["foo", "bar", "baz"] + urls = ["foo.com", "bar.net", "baz.org"] + created_ats = [ + "1929-10-28T09:30:00-05:00", + "2009-01-03T16:39:57-08:00", + "3021-01-21T10:00:00-02:00", + ] + authors = ["Max Mustermann", "John Doe", "Jane Doe"] + embeddings = [[x] * OUTPUT_DIM for x in range(3)] + + for i in range(3): + chunk = DocumentChunk( + id=ids[i], + text=texts[i], + metadata=DocumentChunkMetadata( + document_id=doc_id_1, + source=sources[i], + source_id=source_ids[i], + url=urls[i], + created_at=created_ats[i], + author=authors[i], + ), + embedding=embeddings[i], # type: ignore + ) + + doc_chunks_1.append(chunk) + + doc_id_2 = "merp" + doc_chunks_2 = [] + + ids = ["jkl_123", "lmn_456", "opq_789"] + texts = [ + "3sdsc efac feas sit qweas", + "4wert sdfas fdsc", + "52dsc fdsf eiusmod asdasd incididunt", + ] + sources = [Source.email, Source.file, Source.chat] + source_ids = ["foo", "bar", "baz"] + urls = ["foo.com", "bar.net", "baz.org"] + created_ats = [ + "4929-10-28T09:30:00-05:00", + "5009-01-03T16:39:57-08:00", + "6021-01-21T10:00:00-02:00", + ] + authors = ["Max Mustermann", "John Doe", "Jane Doe"] + embeddings = [[x] * OUTPUT_DIM for x in range(3, 6)] + + for i in range(3): + chunk = DocumentChunk( + id=ids[i], + text=texts[i], + metadata=DocumentChunkMetadata( + document_id=doc_id_2, + source=sources[i], + source_id=source_ids[i], + url=urls[i], + created_at=created_ats[i], + author=authors[i], + ), + embedding=embeddings[i], # type: ignore + ) + + doc_chunks_2.append(chunk) + + return {doc_id_1: doc_chunks_1, doc_id_2: doc_chunks_2} + + +@pytest.mark.asyncio +async def test_upsert(analyticdb_datastore, document_chunk_one): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + query = QueryWithEmbedding( + query="lorem", + top_k=10, + embedding=[0.5] * OUTPUT_DIM, + ) + query_results = await analyticdb_datastore._query(queries=[query]) + assert 3 == len(query_results[0].results) + + +@pytest.mark.asyncio +async def test_reload(analyticdb_datastore, document_chunk_one, document_chunk_two): + await analyticdb_datastore.delete(delete_all=True) + + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + + query = QueryWithEmbedding( + query="lorem", + top_k=10, + embedding=[0.5] * OUTPUT_DIM, + ) + + query_results = await analyticdb_datastore._query(queries=[query]) + assert 3 == len(query_results[0].results) + new_store = AnalyticDBDataStore() + another_in = {i: document_chunk_two[i] for i in document_chunk_two if i != res[0]} + res = await new_store._upsert(another_in) + + query_results = await analyticdb_datastore._query(queries=[query]) + assert 1 == len(query_results) + assert 6 == len(query_results[0].results) + + +@pytest.mark.asyncio +async def test_upsert_query_all(analyticdb_datastore, document_chunk_two): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_two) + assert res == list(document_chunk_two.keys()) + # Num entities currently doesn't track deletes + query = QueryWithEmbedding( + query="lorem", + top_k=10, + embedding=[0.5] * OUTPUT_DIM, + ) + query_results = await analyticdb_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 6 == len(query_results[0].results) + + +@pytest.mark.asyncio +async def test_query_accuracy(analyticdb_datastore, document_chunk_one): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + query = QueryWithEmbedding( + query="lorem", + top_k=1, + embedding=[0] * OUTPUT_DIM, + ) + query_results = await analyticdb_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 1 == len(query_results[0].results) + assert 0 == query_results[0].results[0].score + assert "abc_123" == query_results[0].results[0].id + + +@pytest.mark.asyncio +async def test_query_filter(analyticdb_datastore, document_chunk_one): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + query = QueryWithEmbedding( + query="lorem", + top_k=1, + embedding=[0] * OUTPUT_DIM, + filter=DocumentMetadataFilter( + start_date="2000-01-03T16:39:57-08:00", end_date="2010-01-03T16:39:57-08:00" + ), + ) + query_results = await analyticdb_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 1 == len(query_results[0].results) + assert 0 != query_results[0].results[0].score + assert "def_456" == query_results[0].results[0].id + + +@pytest.mark.asyncio +async def test_delete_with_date_filter(analyticdb_datastore, document_chunk_one): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + await analyticdb_datastore.delete( + filter=DocumentMetadataFilter( + end_date="2009-01-03T16:39:57-08:00", + ) + ) + + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=[0] * OUTPUT_DIM, + ) + query_results = await analyticdb_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 1 == len(query_results[0].results) + assert "ghi_789" == query_results[0].results[0].id + + +@pytest.mark.asyncio +async def test_delete_with_source_filter(analyticdb_datastore, document_chunk_one): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + await analyticdb_datastore.delete( + filter=DocumentMetadataFilter( + source=Source.email, + ) + ) + + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=[0] * OUTPUT_DIM, + ) + query_results = await analyticdb_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 2 == len(query_results[0].results) + assert "def_456" == query_results[0].results[0].id + + +@pytest.mark.asyncio +async def test_delete_with_document_id_filter(analyticdb_datastore, document_chunk_one): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + await analyticdb_datastore.delete( + filter=DocumentMetadataFilter( + document_id=res[0], + ) + ) + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=[0] * OUTPUT_DIM, + ) + query_results = await analyticdb_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 0 == len(query_results[0].results) + + +@pytest.mark.asyncio +async def test_delete_with_document_id(analyticdb_datastore, document_chunk_one): + await analyticdb_datastore.delete(delete_all=True) + res = await analyticdb_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + await analyticdb_datastore.delete([res[0]]) + + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=[0] * OUTPUT_DIM, + ) + query_results = await analyticdb_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 0 == len(query_results[0].results) + + +# if __name__ == '__main__': +# import sys +# import pytest +# pytest.main(sys.argv) diff --git a/tests/datastore/providers/azuresearch/test_azuresearch_datastore.py b/tests/datastore/providers/azuresearch/test_azuresearch_datastore.py new file mode 100644 index 000000000..0a777d3b0 --- /dev/null +++ b/tests/datastore/providers/azuresearch/test_azuresearch_datastore.py @@ -0,0 +1,139 @@ +import pytest +import os +import time +from typing import Union +from azure.search.documents.indexes import SearchIndexClient +from models.models import DocumentMetadataFilter, Query, Source, Document, DocumentMetadata + +AZURESEARCH_TEST_INDEX = "testindex" +os.environ["AZURESEARCH_INDEX"] = AZURESEARCH_TEST_INDEX +if os.environ.get("AZURESEARCH_SERVICE") == None: + os.environ["AZURESEARCH_SERVICE"] = "invalid service name" # Will fail anyway if not set to a real service, but allows tests to be discovered + +import datastore.providers.azuresearch_datastore +from datastore.providers.azuresearch_datastore import AzureSearchDataStore + +@pytest.fixture(scope="module") +def azuresearch_mgmt_client(): + service = os.environ["AZURESEARCH_SERVICE"] + return SearchIndexClient( + endpoint=f"https://{service}.search.windows.net", + credential=AzureSearchDataStore._create_credentials(False) + ) + +def test_translate_filter(): + assert AzureSearchDataStore._translate_filter( + DocumentMetadataFilter() + ) == None + + for field in ["document_id", "source", "source_id", "author"]: + value = Source.file if field == "source" else f"test_{field}" + needs_escaping_value = None if field == "source" else f"test'_{field}" + assert AzureSearchDataStore._translate_filter( + DocumentMetadataFilter(**{field: value}) + ) == f"{field} eq '{value}'" + if needs_escaping_value != None: + assert AzureSearchDataStore._translate_filter( + DocumentMetadataFilter(**{field: needs_escaping_value}) + ) == f"{field} eq 'test''_{field}'" + + assert AzureSearchDataStore._translate_filter( + DocumentMetadataFilter( + document_id = "test_document_id", + source = Source.file, + source_id = "test_source_id", + author = "test_author" + ) + ) == "document_id eq 'test_document_id' and source eq 'file' and source_id eq 'test_source_id' and author eq 'test_author'" + + with pytest.raises(ValueError): + assert AzureSearchDataStore._translate_filter( + DocumentMetadataFilter(start_date="2023-01-01") + ) + with pytest.raises(ValueError): + assert AzureSearchDataStore._translate_filter( + DocumentMetadataFilter(end_date="2023-01-01") + ) + + assert AzureSearchDataStore._translate_filter( + DocumentMetadataFilter(start_date="2023-01-01T00:00:00Z", end_date="2023-01-02T00:00:00Z", document_id = "test_document_id") + ) == "document_id eq 'test_document_id' and created_at ge 2023-01-01T00:00:00Z and created_at le 2023-01-02T00:00:00Z" + +@pytest.mark.asyncio +async def test_lifecycle_hybrid(azuresearch_mgmt_client: SearchIndexClient): + datastore.providers.azuresearch_datastore.AZURESEARCH_DISABLE_HYBRID = None + datastore.providers.azuresearch_datastore.AZURESEARCH_SEMANTIC_CONFIG = None + await lifecycle(azuresearch_mgmt_client) + +@pytest.mark.asyncio +async def test_lifecycle_vectors_only(azuresearch_mgmt_client: SearchIndexClient): + datastore.providers.azuresearch_datastore.AZURESEARCH_DISABLE_HYBRID = "1" + datastore.providers.azuresearch_datastore.AZURESEARCH_SEMANTIC_CONFIG = None + await lifecycle(azuresearch_mgmt_client) + +@pytest.mark.asyncio +async def test_lifecycle_semantic(azuresearch_mgmt_client: SearchIndexClient): + datastore.providers.azuresearch_datastore.AZURESEARCH_DISABLE_HYBRID = None + datastore.providers.azuresearch_datastore.AZURESEARCH_SEMANTIC_CONFIG = "testsemconfig" + await lifecycle(azuresearch_mgmt_client) + +async def lifecycle(azuresearch_mgmt_client: SearchIndexClient): + if AZURESEARCH_TEST_INDEX in azuresearch_mgmt_client.list_index_names(): + azuresearch_mgmt_client.delete_index(AZURESEARCH_TEST_INDEX) + assert AZURESEARCH_TEST_INDEX not in azuresearch_mgmt_client.list_index_names() + try: + store = AzureSearchDataStore() + index = azuresearch_mgmt_client.get_index(AZURESEARCH_TEST_INDEX) + assert index is not None + + result = await store.upsert([ + Document( + id="test_id_1", + text="test text", + metadata=DocumentMetadata(source=Source.file, source_id="test_source_id", author="test_author", created_at="2023-01-01T00:00:00Z", url="http://some-test-url/path")), + Document( + id="test_id_2+", + text="different", + metadata=DocumentMetadata(source=Source.file, source_id="test_source_id", author="test_author", created_at="2023-01-01T00:00:00Z", url="http://some-test-url/path"))]) + assert len(result) == 2 and result[0] == "test_id_1" and result[1] == "test_id_2+" + + # query in a loop in case we need to retry since documents aren't searchable synchronosuly after updates + for _ in range(4): + time.sleep(0.25) + result = await store.query([Query(query="text")]) + if len(result) > 0 and len(result[0].results) > 0: + break + assert len(result) == 1 and len(result[0].results) == 2 + assert result[0].results[0].metadata.document_id == "test_id_1" and result[0].results[1].metadata.document_id == "test_id_2+" + + result = await store.query([Query(query="text", filter=DocumentMetadataFilter(source_id="test_source_id"))]) + assert len(result) == 1 and len(result[0].results) == 2 + assert result[0].results[0].metadata.document_id == "test_id_1" and result[0].results[1].metadata.document_id == "test_id_2+" + + result = await store.query([Query(query="text", filter=DocumentMetadataFilter(source_id="nonexisting_id"))]) + assert len(result) == 1 and len(result[0].results) == 0 + + result = await store.query([Query(query="text", filter=DocumentMetadataFilter(start_date="2023-01-02T00:00:00Z"))]) + assert len(result) == 1 and len(result[0].results) == 0 + + result = await store.query([Query(query="text", filter=DocumentMetadataFilter(start_date="2023-01-01T00:00:00Z"))]) + assert len(result) == 1 and len(result[0].results) == 2 + assert result[0].results[0].metadata.document_id == "test_id_1" and result[0].results[1].metadata.document_id == "test_id_2+" + + result = await store.query([Query(query="text", filter=DocumentMetadataFilter(end_date="2022-12-31T00:00:00Z"))]) + assert len(result) == 1 and len(result[0].results) == 0 + + result = await store.query([Query(query="text", filter=DocumentMetadataFilter(end_date="2023-01-02T00:00:00Z"))]) + assert len(result) == 1 and len(result[0].results) == 2 + assert result[0].results[0].metadata.document_id == "test_id_1" and result[0].results[1].metadata.document_id == "test_id_2+" + + # query in a loop in case we need to retry since documents aren't searchable synchronosuly after updates + assert await store.delete(["test_id_1", "test_id_2+"]) + for _ in range(4): + time.sleep(0.25) + result = await store.query([Query(query="text")]) + if len(result) > 0 and len(result[0].results) == 0: + break + assert len(result) == 1 and len(result[0].results) == 0 + finally: + azuresearch_mgmt_client.delete_index(AZURESEARCH_TEST_INDEX) diff --git a/tests/datastore/providers/chroma/test_chroma_datastore.py b/tests/datastore/providers/chroma/test_chroma_datastore.py new file mode 100644 index 000000000..eacc22ee4 --- /dev/null +++ b/tests/datastore/providers/chroma/test_chroma_datastore.py @@ -0,0 +1,293 @@ +import shutil +from typing import Dict, List +import pytest +import random + +from datastore.providers.chroma_datastore import ChromaDataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + DocumentMetadataFilter, + QueryWithEmbedding, + Source, +) + +TEST_PERSISTENCE_DIR = "chroma_test_datastore" +COLLECTION_NAME = "documents" + + +def ephemeral_chroma_datastore() -> ChromaDataStore: + # Initialize an ephemeral in-memory ChromaDB instance + return ChromaDataStore( + collection_name=COLLECTION_NAME, in_memory=True, persistence_dir=None + ) + + +def persisted_chroma_datastore() -> ChromaDataStore: + # Initialize an in-memory ChromaDB instance with persistence + return ChromaDataStore( + collection_name=COLLECTION_NAME, + in_memory=True, + persistence_dir=TEST_PERSISTENCE_DIR, + ) + + +def get_chroma_datastore() -> ChromaDataStore: + yield ephemeral_chroma_datastore() + yield persisted_chroma_datastore() + # Delete the persistence directory after the test + + +@pytest.fixture(autouse=True) +def cleanup(): + yield + shutil.rmtree(TEST_PERSISTENCE_DIR, ignore_errors=True) + + +# Seed for deterministic testing +random.seed(0) + + +def create_embedding(dim: int) -> List[float]: + return [random.random() for _ in range(dim)] + + +# Data fixtures +TEST_EMBEDDING_DIM = 5 +N_TEST_CHUNKS = 5 + + +@pytest.fixture +def initial_document_chunks() -> Dict[str, List[DocumentChunk]]: + first_doc_chunks = [ + DocumentChunk( + id=f"first-doc-{i}", + text=f"Lorem ipsum {i}", + metadata=DocumentChunkMetadata(), + embedding=create_embedding(TEST_EMBEDDING_DIM), + ) + for i in range(N_TEST_CHUNKS) + ] + return { + "first-doc": first_doc_chunks, + } + + +@pytest.fixture +def document_chunks(initial_document_chunks) -> Dict[str, List[DocumentChunk]]: + doc_chunks = initial_document_chunks + + for k, v in doc_chunks.items(): + for chunk in v: + chunk.metadata = DocumentChunkMetadata( + source=Source.email, created_at="2023-04-03", document_id="first-doc" + ) + chunk.embedding = create_embedding(TEST_EMBEDDING_DIM) + + doc_chunks["second-doc"] = [ + DocumentChunk( + id=f"second-doc-{i}", + text=f"Dolor sit amet {i}", + metadata=DocumentChunkMetadata( + created_at="2023-04-04", document_id="second-doc" + ), + embedding=create_embedding(TEST_EMBEDDING_DIM), + ) + for i in range(N_TEST_CHUNKS) + ] + + return doc_chunks + + +@pytest.mark.asyncio +async def test_add_chunks(document_chunks: Dict[str, List[DocumentChunk]]): + for datastore in get_chroma_datastore(): + await datastore.delete(delete_all=True) + assert datastore._collection.count() == 0 + + print(document_chunks) + + assert await datastore._upsert(document_chunks) == list(document_chunks.keys()) + assert datastore._collection.count() == sum( + len(v) for v in document_chunks.values() + ) + + +@pytest.mark.asyncio +async def test_upsert( + initial_document_chunks: Dict[str, List[DocumentChunk]], + document_chunks: Dict[str, List[DocumentChunk]], +): + for datastore in get_chroma_datastore(): + await datastore.delete(delete_all=True) + + assert await datastore._upsert(initial_document_chunks) == list( + initial_document_chunks.keys() + ) + assert datastore._collection.count() == sum( + len(v) for v in initial_document_chunks.values() + ) + + assert await datastore._upsert(document_chunks) == list(document_chunks.keys()) + assert datastore._collection.count() == sum( + len(v) for v in document_chunks.values() + ) + + +@pytest.mark.asyncio +async def test_add_and_query_all(document_chunks): + for datastore in get_chroma_datastore(): + await datastore.delete(delete_all=True) + + await datastore._upsert(document_chunks) == list(document_chunks.keys()) + + query = QueryWithEmbedding( + query="", + embedding=create_embedding(TEST_EMBEDDING_DIM), + top_k=10, + ) + query_results = await datastore._query(queries=[query]) + assert 1 == len(query_results) + assert 10 == len(query_results[0].results) + + +@pytest.mark.asyncio +async def test_query_accuracy(document_chunks): + for _, v in document_chunks.items(): + for chunk in v: + print(f"id: {chunk.id} emb: {chunk.embedding}") + + def add_noise_to_embedding(embedding: List[float], eps: float = 0) -> List[float]: + return [x + eps * (1.0 - 2 * random.random()) for x in embedding] + + for datastore in get_chroma_datastore(): + await datastore.delete(delete_all=True) + + print(datastore._collection.get(include=["embeddings"])) + + res = await datastore._upsert(document_chunks) + + res = datastore._collection.get(include=["embeddings"]) + for id, emb in zip(res["ids"], res["embeddings"]): + print(f"id: {id} emb: {emb}") + + for _, v in document_chunks.items(): + for chunk in v: + print(f"chunk: {chunk}") + query = QueryWithEmbedding( + query="", + embedding=add_noise_to_embedding(chunk.embedding), + top_k=1, + ) + query_results = await datastore._query(queries=[query]) + print(query_results) + assert query_results[0].results[0].id == chunk.id + + +@pytest.mark.asyncio +async def test_query_filter_by_id(document_chunks): + for datastore in get_chroma_datastore(): + await datastore.delete(delete_all=True) + + await datastore._upsert(document_chunks) + + for doc_id, chunks in document_chunks.items(): + query = QueryWithEmbedding( + query="", + embedding=chunks[0].embedding, + top_k=N_TEST_CHUNKS, + filter=DocumentMetadataFilter(document_id=doc_id), + ) + query_results = await datastore._query(queries=[query]) + # Assert that all document chunks are returned + assert len(query_results[0].results) == len(chunks) + assert all( + [ + result.id in [chunk.id for chunk in chunks] + for result in query_results[0].results + ] + ) + + +@pytest.mark.asyncio +async def test_query_filter_by_date(document_chunks): + for datastore in get_chroma_datastore(): + await datastore.delete(delete_all=True) + + await datastore._upsert(document_chunks) + + # Filter by dates for only the first document + query = QueryWithEmbedding( + query="", + embedding=document_chunks["first-doc"][0].embedding, + top_k=N_TEST_CHUNKS, + filter=DocumentMetadataFilter( + start_date="2023-04-03", end_date="2023-04-03" + ), + ) + + query_results = await datastore._query(queries=[query]) + + # Assert that only the first document is returned + assert len(query_results[0].results) == len(document_chunks["first-doc"]) + assert all( + [ + result.id in [chunk.id for chunk in document_chunks["first-doc"]] + for result in query_results[0].results + ] + ) + + # Filter for the entire date span + query = QueryWithEmbedding( + query="", + embedding=document_chunks["first-doc"][0].embedding, + top_k=N_TEST_CHUNKS * len(document_chunks), + filter=DocumentMetadataFilter( + start_date="2023-04-03", end_date="2023-04-04" + ), + ) + + query_results = await datastore._query(queries=[query]) + + # Assert that both documents are returned + assert len(query_results[0].results) == len(document_chunks["first-doc"]) + len( + document_chunks["second-doc"] + ) + assert all( + [ + result.id + in [chunk.id for chunk in document_chunks["first-doc"]] + + [chunk.id for chunk in document_chunks["second-doc"]] + for result in query_results[0].results + ] + ) + + +@pytest.mark.asyncio +async def test_delete_by_id(document_chunks): + for datastore in get_chroma_datastore(): + await datastore.delete(delete_all=True) + + await datastore._upsert(document_chunks) + + # Delete the first document + await datastore.delete(ids=["first-doc"]) + + # Assert that the first document is deleted + query = QueryWithEmbedding( + query="", + embedding=document_chunks["first-doc"][0].embedding, + top_k=N_TEST_CHUNKS, + ) + query_results = await datastore._query(queries=[query]) + + # Assert that only the second document is still there + query_results = await datastore._query(queries=[query]) + assert len(query_results[0].results) == len(document_chunks["second-doc"]) + + assert all( + [ + result.id in [chunk.id for chunk in document_chunks["second-doc"]] + for result in query_results[0].results + ] + ) diff --git a/tests/datastore/providers/elasticsearch/test_elasticsearch_datastore.py b/tests/datastore/providers/elasticsearch/test_elasticsearch_datastore.py new file mode 100644 index 000000000..8ac451dad --- /dev/null +++ b/tests/datastore/providers/elasticsearch/test_elasticsearch_datastore.py @@ -0,0 +1,158 @@ +import pytest +from models.models import ( + DocumentChunkMetadata, + DocumentMetadataFilter, + DocumentChunk, + QueryWithEmbedding, + Source, +) +from datastore.providers.elasticsearch_datastore import ( + ElasticsearchDataStore, +) +import time + +DIM_SIZE = 1536 + + +@pytest.fixture +def elasticsearch_datastore(): + return ElasticsearchDataStore() + + +def sample_embedding(one_element_poz: int): + embedding = [0] * DIM_SIZE + embedding[one_element_poz % DIM_SIZE] = 1 + return embedding + + +def sample_embeddings(num: int, one_element_start: int = 0): + embeddings = [] + for x in range(num): + embedding = [0] * DIM_SIZE + embedding[(x + one_element_start) % DIM_SIZE] = 1 + embeddings.append(embedding) + return embeddings + + +@pytest.fixture +def document_chunk_one(): + doc_id = "abc" + doc_chunks = [] + + ids = ["123", "456", "789"] + texts = [ + "Aenean euismod bibendum laoreet", + "Vivamus non enim vitae tortor", + "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae", + ] + sources = [Source.email, Source.file, Source.chat] + created_ats = [ + "1929-10-28T09:30:00-05:00", + "2009-01-03T16:39:57-08:00", + "2021-01-21T10:00:00-02:00", + ] + authors = ["Fred Smith", "Bob Doe", "Appleton Doe"] + + embeddings = sample_embeddings(len(texts)) + + for i in range(3): + chunk = DocumentChunk( + id=ids[i], + text=texts[i], + metadata=DocumentChunkMetadata( + document_id=doc_id, + source=sources[i], + created_at=created_ats[i], + author=authors[i], + ), + embedding=embeddings[i], # type: ignore + ) + + doc_chunks.append(chunk) + + return {doc_id: doc_chunks} + + +async def test_upsert(elasticsearch_datastore, document_chunk_one): + await elasticsearch_datastore.delete(delete_all=True) + res = await elasticsearch_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + time.sleep(1) + + results = elasticsearch_datastore.client.search( + index=elasticsearch_datastore.index_name, query={"match_all": {}} + ) + assert results["hits"]["total"]["value"] == 3 + elasticsearch_datastore.client.indices.delete( + index=elasticsearch_datastore.index_name + ) + + +async def test_upsert_query_all(elasticsearch_datastore, document_chunk_one): + await elasticsearch_datastore.delete(delete_all=True) + res = await elasticsearch_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + time.sleep(1) + + query = QueryWithEmbedding( + query="Aenean", + top_k=10, + embedding=sample_embedding(0), # type: ignore + ) + query_results = await elasticsearch_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 3 == len(query_results[0].results) + + +async def test_delete_with_document_id(elasticsearch_datastore, document_chunk_one): + await elasticsearch_datastore.delete(delete_all=True) + res = await elasticsearch_datastore._upsert(document_chunk_one) + time.sleep(1) + assert res == list(document_chunk_one.keys()) + await elasticsearch_datastore.delete([res[0]]) + time.sleep(1) + + query = QueryWithEmbedding( + query="Aenean", + top_k=9, + embedding=sample_embedding(0), # type: ignore + ) + query_results = await elasticsearch_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 0 == len(query_results[0].results) + + elasticsearch_datastore.client.indices.delete( + index=elasticsearch_datastore.index_name + ) + + +async def test_delete_with_source_filter(elasticsearch_datastore, document_chunk_one): + await elasticsearch_datastore.delete(delete_all=True) + res = await elasticsearch_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + time.sleep(1) + + await elasticsearch_datastore.delete( + filter=DocumentMetadataFilter( + source=Source.email, + ) + ) + + time.sleep(1) + + query = QueryWithEmbedding( + query="Aenean", + top_k=9, + embedding=sample_embedding(0), # type: ignore + ) + query_results = await elasticsearch_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 2 == len(query_results[0].results) + assert "456" == query_results[0].results[0].id + + elasticsearch_datastore.client.indices.delete( + index=elasticsearch_datastore.index_name + ) diff --git a/tests/datastore/providers/llama/test_llama_datastore.py b/tests/datastore/providers/llama/test_llama_datastore.py new file mode 100644 index 000000000..3039caf0d --- /dev/null +++ b/tests/datastore/providers/llama/test_llama_datastore.py @@ -0,0 +1,95 @@ +from typing import Dict, List +import pytest +from datastore.providers.llama_datastore import LlamaDataStore +from models.models import DocumentChunk, DocumentChunkMetadata, QueryWithEmbedding + + +def create_embedding(non_zero_pos: int, size: int) -> List[float]: + vector = [0.0] * size + vector[non_zero_pos % size] = 1.0 + return vector + + +@pytest.fixture +def initial_document_chunks() -> Dict[str, List[DocumentChunk]]: + first_doc_chunks = [ + DocumentChunk( + id=f"first-doc-{i}", + text=f"Lorem ipsum {i}", + metadata=DocumentChunkMetadata(), + embedding=create_embedding(i, 5), + ) + for i in range(4, 7) + ] + return { + "first-doc": first_doc_chunks, + } + + +@pytest.fixture +def queries() -> List[QueryWithEmbedding]: + queries = [ + QueryWithEmbedding( + query='Query 1', + top_k=1, + embedding=create_embedding(4, 5), + ), + QueryWithEmbedding( + query='Query 2', + top_k=2, + embedding=create_embedding(5, 5), + ), + ] + return queries + + +@pytest.fixture +def llama_datastore() -> LlamaDataStore: + return LlamaDataStore() + +@pytest.mark.asyncio +async def test_upsert( + llama_datastore: LlamaDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]] +) -> None: + """Test basic upsert.""" + doc_ids = await llama_datastore._upsert(initial_document_chunks) + assert doc_ids == [doc_id for doc_id in initial_document_chunks] + + +@pytest.mark.asyncio +async def test_query( + llama_datastore: LlamaDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], + queries: List[QueryWithEmbedding], +) -> None: + """Test basic query.""" + # insert to prepare for test + await llama_datastore._upsert(initial_document_chunks) + + query_results = await llama_datastore._query(queries) + assert len(query_results) == len(queries) + + query_0_results = query_results[0].results + query_1_results = query_results[1].results + + assert len(query_0_results) == 1 + assert len(query_1_results) == 2 + + # NOTE: this is the correct behavior + assert query_0_results[0].id == 'first-doc-4' + assert query_1_results[0].id == 'first-doc-5' + assert query_1_results[1].id == 'first-doc-4' + + +@pytest.mark.asyncio +async def test_delete( + llama_datastore: LlamaDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], +) -> None: + # insert to prepare for test + await llama_datastore._upsert(initial_document_chunks) + + is_success = llama_datastore.delete(['first-doc']) + assert is_success + diff --git a/tests/datastore/providers/milvus/test_milvus_datastore.py b/tests/datastore/providers/milvus/test_milvus_datastore.py new file mode 100644 index 000000000..d15b1a007 --- /dev/null +++ b/tests/datastore/providers/milvus/test_milvus_datastore.py @@ -0,0 +1,354 @@ +# from pathlib import Path +# from dotenv import find_dotenv, load_dotenv +# env_path = Path(".") / "milvus.env" +# load_dotenv(dotenv_path=env_path, verbose=True) + +import pytest +from models.models import ( + DocumentChunkMetadata, + DocumentMetadataFilter, + DocumentChunk, + QueryWithEmbedding, + Source, +) +from datastore.providers.milvus_datastore import ( + OUTPUT_DIM, + MilvusDataStore, +) + + +@pytest.fixture +def milvus_datastore(): + return MilvusDataStore(consistency_level = "Strong") + + +def sample_embedding(one_element_poz: int): + embedding = [0] * OUTPUT_DIM + embedding[one_element_poz % OUTPUT_DIM] = 1 + return embedding + +def sample_embeddings(num: int, one_element_start: int = 0): + # since metric type is consine, we create vector contains only one element 1, others 0 + embeddings = [] + for x in range(num): + embedding = [0] * OUTPUT_DIM + embedding[(x + one_element_start) % OUTPUT_DIM] = 1 + embeddings.append(embedding) + return embeddings + +@pytest.fixture +def document_chunk_one(): + doc_id = "zerp" + doc_chunks = [] + + ids = ["abc_123", "def_456", "ghi_789"] + texts = [ + "lorem ipsum dolor sit amet", + "consectetur adipiscing elit", + "sed do eiusmod tempor incididunt", + ] + sources = [Source.email, Source.file, Source.chat] + source_ids = ["foo", "bar", "baz"] + urls = ["foo.com", "bar.net", "baz.org"] + created_ats = [ + "1929-10-28T09:30:00-05:00", + "2009-01-03T16:39:57-08:00", + "2021-01-21T10:00:00-02:00", + ] + authors = ["Max Mustermann", "John Doe", "Jane Doe"] + + embeddings = sample_embeddings(len(texts)) + + for i in range(3): + chunk = DocumentChunk( + id=ids[i], + text=texts[i], + metadata=DocumentChunkMetadata( + document_id=doc_id, + source=sources[i], + source_id=source_ids[i], + url=urls[i], + created_at=created_ats[i], + author=authors[i], + ), + embedding=embeddings[i], # type: ignore + ) + + doc_chunks.append(chunk) + + return {doc_id: doc_chunks} + + +@pytest.fixture +def document_chunk_two(): + doc_id_1 = "zerp" + doc_chunks_1 = [] + + ids = ["abc_123", "def_456", "ghi_789"] + texts = [ + "1lorem ipsum dolor sit amet", + "2consectetur adipiscing elit", + "3sed do eiusmod tempor incididunt", + ] + sources = [Source.email, Source.file, Source.chat] + source_ids = ["foo", "bar", "baz"] + urls = ["foo.com", "bar.net", "baz.org"] + created_ats = [ + "1929-10-28T09:30:00-05:00", + "2009-01-03T16:39:57-08:00", + "3021-01-21T10:00:00-02:00", + ] + authors = ["Max Mustermann", "John Doe", "Jane Doe"] + embeddings = sample_embeddings(len(texts)) + + for i in range(3): + chunk = DocumentChunk( + id=ids[i], + text=texts[i], + metadata=DocumentChunkMetadata( + document_id=doc_id_1, + source=sources[i], + source_id=source_ids[i], + url=urls[i], + created_at=created_ats[i], + author=authors[i], + ), + embedding=embeddings[i], # type: ignore + ) + + doc_chunks_1.append(chunk) + + doc_id_2 = "merp" + doc_chunks_2 = [] + + ids = ["jkl_123", "lmn_456", "opq_789"] + texts = [ + "3sdsc efac feas sit qweas", + "4wert sdfas fdsc", + "52dsc fdsf eiusmod asdasd incididunt", + ] + sources = [Source.email, Source.file, Source.chat] + source_ids = ["foo", "bar", "baz"] + urls = ["foo.com", "bar.net", "baz.org"] + created_ats = [ + "4929-10-28T09:30:00-05:00", + "5009-01-03T16:39:57-08:00", + "6021-01-21T10:00:00-02:00", + ] + authors = ["Max Mustermann", "John Doe", "Jane Doe"] + embeddings = sample_embeddings(len(texts), 3) + + for i in range(3): + chunk = DocumentChunk( + id=ids[i], + text=texts[i], + metadata=DocumentChunkMetadata( + document_id=doc_id_2, + source=sources[i], + source_id=source_ids[i], + url=urls[i], + created_at=created_ats[i], + author=authors[i], + ), + embedding=embeddings[i], # type: ignore + ) + + doc_chunks_2.append(chunk) + + return {doc_id_1: doc_chunks_1, doc_id_2: doc_chunks_2} + + +@pytest.mark.asyncio +async def test_upsert(milvus_datastore, document_chunk_one): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + assert 3 == milvus_datastore.col.num_entities + milvus_datastore.col.drop() + + +@pytest.mark.asyncio +async def test_reload(milvus_datastore, document_chunk_one, document_chunk_two): + await milvus_datastore.delete(delete_all=True) + + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + assert 3 == milvus_datastore.col.num_entities + + new_store = MilvusDataStore() + another_in = {i: document_chunk_two[i] for i in document_chunk_two if i != res[0]} + res = await new_store._upsert(another_in) + new_store.col.flush() + assert 6 == new_store.col.num_entities + query = QueryWithEmbedding( + query="lorem", + top_k=10, + embedding=sample_embedding(0), + ) + query_results = await milvus_datastore._query(queries=[query]) + assert 1 == len(query_results) + new_store.col.drop() + + +@pytest.mark.asyncio +async def test_upsert_query_all(milvus_datastore, document_chunk_two): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_two) + assert res == list(document_chunk_two.keys()) + milvus_datastore.col.flush() + + # Num entities currently doesn't track deletes + query = QueryWithEmbedding( + query="lorem", + top_k=10, + embedding=sample_embedding(0), + ) + query_results = await milvus_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 6 == len(query_results[0].results) + milvus_datastore.col.drop() + + +@pytest.mark.asyncio +async def test_query_accuracy(milvus_datastore, document_chunk_one): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + query = QueryWithEmbedding( + query="lorem", + top_k=1, + embedding=sample_embedding(0), + ) + query_results = await milvus_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 1 == len(query_results[0].results) + assert 1.0 == query_results[0].results[0].score + assert "abc_123" == query_results[0].results[0].id + milvus_datastore.col.drop() + + +@pytest.mark.asyncio +async def test_query_filter(milvus_datastore, document_chunk_one): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + query = QueryWithEmbedding( + query="lorem", + top_k=1, + embedding=sample_embedding(0), + filter=DocumentMetadataFilter( + start_date="2000-01-03T16:39:57-08:00", end_date="2010-01-03T16:39:57-08:00" + ), + ) + query_results = await milvus_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 1 == len(query_results[0].results) + assert 1.0 != query_results[0].results[0].score + assert "def_456" == query_results[0].results[0].id + milvus_datastore.col.drop() + + +@pytest.mark.asyncio +async def test_delete_with_date_filter(milvus_datastore, document_chunk_one): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + await milvus_datastore.delete( + filter=DocumentMetadataFilter( + end_date="2009-01-03T16:39:57-08:00", + ) + ) + + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=sample_embedding(0), + ) + query_results = await milvus_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 1 == len(query_results[0].results) + assert "ghi_789" == query_results[0].results[0].id + milvus_datastore.col.drop() + + +@pytest.mark.asyncio +async def test_delete_with_source_filter(milvus_datastore, document_chunk_one): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + await milvus_datastore.delete( + filter=DocumentMetadataFilter( + source=Source.email, + ) + ) + + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=sample_embedding(0), + ) + query_results = await milvus_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 2 == len(query_results[0].results) + assert "def_456" == query_results[0].results[0].id + milvus_datastore.col.drop() + + +@pytest.mark.asyncio +async def test_delete_with_document_id_filter(milvus_datastore, document_chunk_one): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + await milvus_datastore.delete( + filter=DocumentMetadataFilter( + document_id=res[0], + ) + ) + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=sample_embedding(0), + ) + query_results = await milvus_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 0 == len(query_results[0].results) + milvus_datastore.col.drop() + + +@pytest.mark.asyncio +async def test_delete_with_document_id(milvus_datastore, document_chunk_one): + await milvus_datastore.delete(delete_all=True) + res = await milvus_datastore._upsert(document_chunk_one) + assert res == list(document_chunk_one.keys()) + milvus_datastore.col.flush() + await milvus_datastore.delete([res[0]]) + + query = QueryWithEmbedding( + query="lorem", + top_k=9, + embedding=sample_embedding(0), + ) + query_results = await milvus_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 0 == len(query_results[0].results) + milvus_datastore.col.drop() + + +# if __name__ == '__main__': +# import sys +# import pytest +# pytest.main(sys.argv) diff --git a/tests/datastore/providers/postgres/test_postgres_datastore.py b/tests/datastore/providers/postgres/test_postgres_datastore.py new file mode 100644 index 000000000..1e4f0a847 --- /dev/null +++ b/tests/datastore/providers/postgres/test_postgres_datastore.py @@ -0,0 +1,291 @@ +from typing import Dict, List +import pytest +from datastore.providers.postgres_datastore import PostgresDataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + DocumentMetadataFilter, + QueryWithEmbedding, +) + + +def create_embedding(non_zero_pos: int) -> List[float]: + # create a vector with a single non-zero value of dimension 1535 + vector = [0.0] * 1536 + vector[non_zero_pos - 1] = 1.0 + return vector + + +@pytest.fixture +def initial_document_chunks() -> Dict[str, List[DocumentChunk]]: + first_doc_chunks = [ + DocumentChunk( + id=f"first-doc-{i}", + text=f"Lorem ipsum {i}", + metadata=DocumentChunkMetadata(), + embedding=create_embedding(i), + ) + for i in range(4, 7) + ] + return { + "first-doc": first_doc_chunks, + } + + +@pytest.fixture +def queries() -> List[QueryWithEmbedding]: + queries = [ + QueryWithEmbedding( + query="Query 1", + top_k=1, + embedding=create_embedding(4), + ), + QueryWithEmbedding( + query="Query 2", + top_k=2, + embedding=create_embedding(5), + ), + ] + return queries + + +@pytest.fixture +def postgres_datastore() -> PostgresDataStore: + return PostgresDataStore() + + +@pytest.mark.asyncio +async def test_upsert( + postgres_datastore: PostgresDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], +) -> None: + """Test basic upsert.""" + doc_ids = await postgres_datastore._upsert(initial_document_chunks) + assert doc_ids == [doc_id for doc_id in initial_document_chunks] + + +@pytest.mark.asyncio +async def test_query( + postgres_datastore: PostgresDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], + queries: List[QueryWithEmbedding], +) -> None: + """Test basic query.""" + # insert to prepare for test + await postgres_datastore._upsert(initial_document_chunks) + + query_results = await postgres_datastore._query(queries) + assert len(query_results) == len(queries) + + query_0_results = query_results[0].results + query_1_results = query_results[1].results + + assert len(query_0_results) == 1 + assert len(query_1_results) == 2 + + # NOTE: this is the correct behavior + assert query_0_results[0].id == "first-doc-4" + assert query_1_results[0].id == "first-doc-5" + assert query_1_results[1].id == "first-doc-4" + + +@pytest.mark.asyncio +async def test_delete( + postgres_datastore: PostgresDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], +) -> None: + # insert to prepare for test + await postgres_datastore._upsert(initial_document_chunks) + + is_success = await postgres_datastore.delete(["first-doc"]) + assert is_success + + +@pytest.mark.asyncio +async def test_upsert_new_chunk(postgres_datastore): + await postgres_datastore.delete(delete_all=True) + chunk = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + ids = await postgres_datastore._upsert({"doc1": [chunk]}) + assert len(ids) == 1 + + +@pytest.mark.asyncio +async def test_upsert_existing_chunk(postgres_datastore): + await postgres_datastore.delete(delete_all=True) + chunk = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + ids = await postgres_datastore._upsert({"doc1": [chunk]}) + + chunk = DocumentChunk( + id="chunk1", + text="New text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + ids = await postgres_datastore._upsert({"doc1": [chunk]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + top_k=1, + ) + results = await postgres_datastore._query([query]) + + assert len(ids) == 1 + assert len(results[0].results) == 1 + assert results[0].results[0].id == "chunk1" + assert results[0].results[0].text == "New text" + + +@pytest.mark.asyncio +async def test_query_score(postgres_datastore): + await postgres_datastore.delete(delete_all=True) + chunk1 = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + chunk2 = DocumentChunk( + id="chunk2", + text="Another text", + embedding=[-1 if i % 2 == 0 else 1 for i in range(1536)], + metadata=DocumentChunkMetadata(), + ) + await postgres_datastore._upsert({"doc1": [chunk1], "doc2": [chunk2]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + ) + results = await postgres_datastore._query([query]) + + assert results[0].results[0].id == "chunk1" + assert int(results[0].results[0].score) == 1536 + + +@pytest.mark.asyncio +async def test_query_filter(postgres_datastore): + await postgres_datastore.delete(delete_all=True) + chunk1 = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata( + source="email", created_at="2021-01-01", author="John" + ), + ) + chunk2 = DocumentChunk( + id="chunk2", + text="Another text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata( + source="chat", created_at="2022-02-02", author="Mike" + ), + ) + await postgres_datastore._upsert({"doc1": [chunk1], "doc2": [chunk2]}) + + # Test author filter -- string + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + filter=DocumentMetadataFilter(author="John"), + ) + results = await postgres_datastore._query([query]) + assert results[0].results[0].id == "chunk1" + + # Test source filter -- enum + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + filter=DocumentMetadataFilter(source="chat"), + ) + results = await postgres_datastore._query([query]) + assert results[0].results[0].id == "chunk2" + + # Test created_at filter -- date + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + filter=DocumentMetadataFilter(start_date="2022-01-01"), + ) + results = await postgres_datastore._query([query]) + assert results[0].results[0].id == "chunk2" + + +@pytest.mark.asyncio +async def test_delete(postgres_datastore): + await postgres_datastore.delete(delete_all=True) + chunk1 = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + chunk2 = DocumentChunk( + id="chunk2", + text="Another text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + await postgres_datastore._upsert({"doc1": [chunk1], "doc2": [chunk2]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Another query", + embedding=query_embedding, + ) + results = await postgres_datastore._query([query]) + + assert len(results[0].results) == 2 + assert results[0].results[0].id == "chunk1" + assert results[0].results[1].id == "chunk2" + + await postgres_datastore.delete(ids=["doc1"]) + results_after_delete = await postgres_datastore._query([query]) + + assert len(results_after_delete[0].results) == 1 + assert results_after_delete[0].results[0].id == "chunk2" + + +@pytest.mark.asyncio +async def test_delete_all(postgres_datastore): + await postgres_datastore.delete(delete_all=True) + chunk = DocumentChunk( + id="chunk", + text="Another text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + await postgres_datastore._upsert({"doc": [chunk]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Another query", + embedding=query_embedding, + top_k=1, + ) + results = await postgres_datastore._query([query]) + + assert len(results) == 1 + assert len(results[0].results) == 1 + assert results[0].results[0].id == "chunk" + + await postgres_datastore.delete(delete_all=True) + results_after_delete = await postgres_datastore._query([query]) + + assert len(results_after_delete[0].results) == 0 diff --git a/tests/datastore/providers/qdrant/test_qdrant_datastore.py b/tests/datastore/providers/qdrant/test_qdrant_datastore.py new file mode 100644 index 000000000..850e0a936 --- /dev/null +++ b/tests/datastore/providers/qdrant/test_qdrant_datastore.py @@ -0,0 +1,280 @@ +from typing import Dict, List + +import pytest +import qdrant_client +from qdrant_client.http.models import PayloadSchemaType + +from datastore.providers.qdrant_datastore import QdrantDataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + QueryWithEmbedding, + DocumentMetadataFilter, + Source, +) + + +def create_embedding(non_zero_pos: int, size: int) -> List[float]: + vector = [0.0] * size + vector[non_zero_pos % size] = 1.0 + return vector + + +@pytest.fixture +def qdrant_datastore() -> QdrantDataStore: + return QdrantDataStore( + collection_name="documents", vector_size=5, recreate_collection=True + ) + + +@pytest.fixture +def client() -> qdrant_client.QdrantClient: + return qdrant_client.QdrantClient() + + +@pytest.fixture +def initial_document_chunks() -> Dict[str, List[DocumentChunk]]: + first_doc_chunks = [ + DocumentChunk( + id=f"first-doc-{i}", + text=f"Lorem ipsum {i}", + metadata=DocumentChunkMetadata(), + embedding=create_embedding(i, 5), + ) + for i in range(4, 7) + ] + return { + "first-doc": first_doc_chunks, + } + + +@pytest.fixture +def document_chunks() -> Dict[str, List[DocumentChunk]]: + first_doc_chunks = [ + DocumentChunk( + id=f"first-doc_{i}", + text=f"Lorem ipsum {i}", + metadata=DocumentChunkMetadata( + source=Source.email, created_at="2023-03-05", document_id="first-doc" + ), + embedding=create_embedding(i, 5), + ) + for i in range(3) + ] + second_doc_chunks = [ + DocumentChunk( + id=f"second-doc_{i}", + text=f"Dolor sit amet {i}", + metadata=DocumentChunkMetadata( + created_at="2023-03-04", document_id="second-doc" + ), + embedding=create_embedding(i + len(first_doc_chunks), 5), + ) + for i in range(2) + ] + return { + "first-doc": first_doc_chunks, + "second-doc": second_doc_chunks, + } + + +@pytest.mark.asyncio +async def test_datastore_creates_payload_indexes( + qdrant_datastore, + client, +): + collection_info = client.get_collection(collection_name="documents") + + assert 2 == len(collection_info.payload_schema) + assert "created_at" in collection_info.payload_schema + created_at = collection_info.payload_schema["created_at"] + assert PayloadSchemaType.INTEGER == created_at.data_type + assert "metadata.document_id" in collection_info.payload_schema + document_id = collection_info.payload_schema["metadata.document_id"] + assert PayloadSchemaType.KEYWORD == document_id.data_type + + +@pytest.mark.asyncio +async def test_upsert_creates_all_points( + qdrant_datastore, + client, + document_chunks, +): + document_ids = await qdrant_datastore._upsert(document_chunks) + + assert 2 == len(document_ids) + assert 5 == client.count(collection_name="documents").count + + +@pytest.mark.asyncio +async def test_upsert_does_not_remove_existing_documents_but_store_new( + qdrant_datastore, + client, + initial_document_chunks, + document_chunks, +): + """ + This test ensures calling ._upsert no longer removes the existing document chunks, + as they are currently removed in the .upsert method directly. + """ + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(initial_document_chunks) + + await qdrant_datastore._upsert(document_chunks) + + assert 8 == client.count(collection_name="documents").count + + +@pytest.mark.asyncio +async def test_query_returns_all_on_single_query(qdrant_datastore, document_chunks): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + query = QueryWithEmbedding( + query="lorem", + top_k=5, + embedding=[0.5, 0.5, 0.5, 0.5, 0.5], + ) + query_results = await qdrant_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert "lorem" == query_results[0].query + assert 5 == len(query_results[0].results) + + +@pytest.mark.asyncio +async def test_query_returns_closest_entry(qdrant_datastore, document_chunks): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + query = QueryWithEmbedding( + query="ipsum", + top_k=1, + embedding=[0.0, 0.0, 0.5, 0.0, 0.0], + ) + query_results = await qdrant_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert "ipsum" == query_results[0].query + assert 1 == len(query_results[0].results) + first_document_chunk = query_results[0].results[0] + assert 0.0 <= first_document_chunk.score <= 1.0 + assert Source.email == first_document_chunk.metadata.source + assert "2023-03-05" == first_document_chunk.metadata.created_at + assert "first-doc" == first_document_chunk.metadata.document_id + + +@pytest.mark.asyncio +async def test_query_filter_by_document_id_returns_this_document_chunks( + qdrant_datastore, document_chunks +): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + first_query = QueryWithEmbedding( + query="dolor", + filter=DocumentMetadataFilter(document_id="first-doc"), + top_k=5, + embedding=[0.0, 0.0, 0.5, 0.0, 0.0], + ) + second_query = QueryWithEmbedding( + query="dolor", + filter=DocumentMetadataFilter(document_id="second-doc"), + top_k=5, + embedding=[0.0, 0.0, 0.5, 0.0, 0.0], + ) + query_results = await qdrant_datastore._query(queries=[first_query, second_query]) + + assert 2 == len(query_results) + assert "dolor" == query_results[0].query + assert "dolor" == query_results[1].query + assert 3 == len(query_results[0].results) + assert 2 == len(query_results[1].results) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("start_date", ["2023-03-05T00:00:00", "2023-03-05"]) +async def test_query_start_date_converts_datestring( + qdrant_datastore, + document_chunks, + start_date, +): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + query = QueryWithEmbedding( + query="sit amet", + filter=DocumentMetadataFilter(start_date=start_date), + top_k=5, + embedding=[0.0, 0.0, 0.5, 0.0, 0.0], + ) + query_results = await qdrant_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 3 == len(query_results[0].results) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("end_date", ["2023-03-04T00:00:00", "2023-03-04"]) +async def test_query_end_date_converts_datestring( + qdrant_datastore, + document_chunks, + end_date, +): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + query = QueryWithEmbedding( + query="sit amet", + filter=DocumentMetadataFilter(end_date=end_date), + top_k=5, + embedding=[0.0, 0.0, 0.5, 0.0, 0.0], + ) + query_results = await qdrant_datastore._query(queries=[query]) + + assert 1 == len(query_results) + assert 2 == len(query_results[0].results) + + +@pytest.mark.asyncio +async def test_delete_removes_by_ids( + qdrant_datastore, + client, + document_chunks, +): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + await qdrant_datastore.delete(ids=["first-doc"]) + + assert 2 == client.count(collection_name="documents").count + + +@pytest.mark.asyncio +async def test_delete_removes_by_document_id_filter( + qdrant_datastore, + client, + document_chunks, +): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + await qdrant_datastore.delete( + filter=DocumentMetadataFilter(document_id="first-doc") + ) + + assert 2 == client.count(collection_name="documents").count + + +@pytest.mark.asyncio +async def test_delete_removes_all( + qdrant_datastore, + client, + document_chunks, +): + # Fill the database with document chunks before running the actual test + await qdrant_datastore._upsert(document_chunks) + + await qdrant_datastore.delete(delete_all=True) + + assert 0 == client.count(collection_name="documents").count diff --git a/tests/datastore/providers/redis/test_redis_datastore.py b/tests/datastore/providers/redis/test_redis_datastore.py new file mode 100644 index 000000000..6d899881c --- /dev/null +++ b/tests/datastore/providers/redis/test_redis_datastore.py @@ -0,0 +1,64 @@ +from datastore.providers.redis_datastore import RedisDataStore +from models.models import DocumentChunk, DocumentChunkMetadata, QueryWithEmbedding, Source, DocumentMetadataFilter +import pytest +import redis.asyncio as redis +import numpy as np + +NUM_TEST_DOCS = 10 + +@pytest.fixture +async def redis_datastore(): + return await RedisDataStore.init(dim=5) + +def create_embedding(i, dim): + vec = np.array([0.1] * dim).astype(np.float64).tolist() + vec[dim-1] = i+1/10 + return vec + +def create_document_chunk(i, dim): + return DocumentChunk( + id=f"first-doc_{i}", + text=f"Lorem ipsum {i}", + embedding=create_embedding(i, dim), + metadata=DocumentChunkMetadata( + source=Source.file, created_at="1970-01-01", document_id="docs" + ), + ) + +def create_document_chunks(n, dim): + docs = [create_document_chunk(i, dim) for i in range(n)] + return {"docs": docs} + +@pytest.mark.asyncio +async def test_redis_upsert_query(redis_datastore): + docs = create_document_chunks(NUM_TEST_DOCS, 5) + await redis_datastore._upsert(docs) + query = QueryWithEmbedding( + query="Lorem ipsum 0", + top_k=5, + embedding= create_embedding(0, 5), + ) + query_results = await redis_datastore._query(queries=[query]) + assert 1 == len(query_results) + for i in range(5): + assert f"Lorem ipsum {i}" == query_results[0].results[i].text + assert "docs" == query_results[0].results[i].id + +@pytest.mark.asyncio +async def test_redis_filter_query(redis_datastore): + query = QueryWithEmbedding( + query="Lorem ipsum 0", + filter=DocumentMetadataFilter(document_id="docs"), + top_k=5, + embedding= create_embedding(0, 5), + ) + query_results = await redis_datastore._query(queries=[query]) + print(query_results) + assert 1 == len(query_results) + assert "docs" == query_results[0].results[0].id + + +@pytest.mark.asyncio +async def test_redis_delete_docs(redis_datastore): + res = await redis_datastore.delete(ids=["docs"]) + assert res diff --git a/tests/datastore/providers/supabase/test_supabase_datastore.py b/tests/datastore/providers/supabase/test_supabase_datastore.py new file mode 100644 index 000000000..0fff42559 --- /dev/null +++ b/tests/datastore/providers/supabase/test_supabase_datastore.py @@ -0,0 +1,291 @@ +from typing import Dict, List +import pytest +from datastore.providers.supabase_datastore import SupabaseDataStore +from models.models import ( + DocumentChunk, + DocumentChunkMetadata, + DocumentMetadataFilter, + QueryWithEmbedding, +) + + +def create_embedding(non_zero_pos: int) -> List[float]: + # create a vector with a single non-zero value of dimension 1535 + vector = [0.0] * 1536 + vector[non_zero_pos - 1] = 1.0 + return vector + + +@pytest.fixture +def initial_document_chunks() -> Dict[str, List[DocumentChunk]]: + first_doc_chunks = [ + DocumentChunk( + id=f"first-doc-{i}", + text=f"Lorem ipsum {i}", + metadata=DocumentChunkMetadata(), + embedding=create_embedding(i), + ) + for i in range(4, 7) + ] + return { + "first-doc": first_doc_chunks, + } + + +@pytest.fixture +def queries() -> List[QueryWithEmbedding]: + queries = [ + QueryWithEmbedding( + query="Query 1", + top_k=1, + embedding=create_embedding(4), + ), + QueryWithEmbedding( + query="Query 2", + top_k=2, + embedding=create_embedding(5), + ), + ] + return queries + + +@pytest.fixture +def supabase_datastore() -> SupabaseDataStore: + return SupabaseDataStore() + + +@pytest.mark.asyncio +async def test_upsert( + supabase_datastore: SupabaseDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], +) -> None: + """Test basic upsert.""" + doc_ids = await supabase_datastore._upsert(initial_document_chunks) + assert doc_ids == [doc_id for doc_id in initial_document_chunks] + + +@pytest.mark.asyncio +async def test_query( + supabase_datastore: SupabaseDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], + queries: List[QueryWithEmbedding], +) -> None: + """Test basic query.""" + # insert to prepare for test + await supabase_datastore._upsert(initial_document_chunks) + + query_results = await supabase_datastore._query(queries) + assert len(query_results) == len(queries) + + query_0_results = query_results[0].results + query_1_results = query_results[1].results + + assert len(query_0_results) == 1 + assert len(query_1_results) == 2 + + # NOTE: this is the correct behavior + assert query_0_results[0].id == "first-doc-4" + assert query_1_results[0].id == "first-doc-5" + assert query_1_results[1].id == "first-doc-4" + + +@pytest.mark.asyncio +async def test_delete( + supabase_datastore: SupabaseDataStore, + initial_document_chunks: Dict[str, List[DocumentChunk]], +) -> None: + # insert to prepare for test + await supabase_datastore._upsert(initial_document_chunks) + + is_success = await supabase_datastore.delete(["first-doc"]) + assert is_success + + +@pytest.mark.asyncio +async def test_upsert_new_chunk(supabase_datastore): + await supabase_datastore.delete(delete_all=True) + chunk = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + ids = await supabase_datastore._upsert({"doc1": [chunk]}) + assert len(ids) == 1 + + +@pytest.mark.asyncio +async def test_upsert_existing_chunk(supabase_datastore): + await supabase_datastore.delete(delete_all=True) + chunk = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + ids = await supabase_datastore._upsert({"doc1": [chunk]}) + + chunk = DocumentChunk( + id="chunk1", + text="New text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + ids = await supabase_datastore._upsert({"doc1": [chunk]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + top_k=1, + ) + results = await supabase_datastore._query([query]) + + assert len(ids) == 1 + assert len(results[0].results) == 1 + assert results[0].results[0].id == "chunk1" + assert results[0].results[0].text == "New text" + + +@pytest.mark.asyncio +async def test_query_score(supabase_datastore): + await supabase_datastore.delete(delete_all=True) + chunk1 = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + chunk2 = DocumentChunk( + id="chunk2", + text="Another text", + embedding=[-1 if i % 2 == 0 else 1 for i in range(1536)], + metadata=DocumentChunkMetadata(), + ) + await supabase_datastore._upsert({"doc1": [chunk1], "doc2": [chunk2]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + ) + results = await supabase_datastore._query([query]) + + assert results[0].results[0].id == "chunk1" + assert int(results[0].results[0].score) == 1536 + + +@pytest.mark.asyncio +async def test_query_filter(supabase_datastore): + await supabase_datastore.delete(delete_all=True) + chunk1 = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata( + source="email", created_at="2021-01-01", author="John" + ), + ) + chunk2 = DocumentChunk( + id="chunk2", + text="Another text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata( + source="chat", created_at="2022-02-02", author="Mike" + ), + ) + await supabase_datastore._upsert({"doc1": [chunk1], "doc2": [chunk2]}) + + # Test author filter -- string + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + filter=DocumentMetadataFilter(author="John"), + ) + results = await supabase_datastore._query([query]) + assert results[0].results[0].id == "chunk1" + + # Test source filter -- enum + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + filter=DocumentMetadataFilter(source="chat"), + ) + results = await supabase_datastore._query([query]) + assert results[0].results[0].id == "chunk2" + + # Test created_at filter -- date + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Query", + embedding=query_embedding, + filter=DocumentMetadataFilter(start_date="2022-01-01"), + ) + results = await supabase_datastore._query([query]) + assert results[0].results[0].id == "chunk2" + + +@pytest.mark.asyncio +async def test_delete(supabase_datastore): + await supabase_datastore.delete(delete_all=True) + chunk1 = DocumentChunk( + id="chunk1", + text="Sample text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + chunk2 = DocumentChunk( + id="chunk2", + text="Another text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + await supabase_datastore._upsert({"doc1": [chunk1], "doc2": [chunk2]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Another query", + embedding=query_embedding, + ) + results = await supabase_datastore._query([query]) + + assert len(results[0].results) == 2 + assert results[0].results[0].id == "chunk1" + assert results[0].results[1].id == "chunk2" + + await supabase_datastore.delete(ids=["doc1"]) + results_after_delete = await supabase_datastore._query([query]) + + assert len(results_after_delete[0].results) == 1 + assert results_after_delete[0].results[0].id == "chunk2" + + +@pytest.mark.asyncio +async def test_delete_all(supabase_datastore): + await supabase_datastore.delete(delete_all=True) + chunk = DocumentChunk( + id="chunk", + text="Another text", + embedding=[1] * 1536, + metadata=DocumentChunkMetadata(), + ) + await supabase_datastore._upsert({"doc": [chunk]}) + + query_embedding = [1] * 1536 + query = QueryWithEmbedding( + query="Another query", + embedding=query_embedding, + top_k=1, + ) + results = await supabase_datastore._query([query]) + + assert len(results) == 1 + assert len(results[0].results) == 1 + assert results[0].results[0].id == "chunk" + + await supabase_datastore.delete(delete_all=True) + results_after_delete = await supabase_datastore._query([query]) + + assert len(results_after_delete[0].results) == 0 diff --git a/tests/datastore/providers/weaviate/docker-compose.yml b/tests/datastore/providers/weaviate/docker-compose.yml new file mode 100644 index 000000000..1900aa580 --- /dev/null +++ b/tests/datastore/providers/weaviate/docker-compose.yml @@ -0,0 +1,25 @@ +--- +version: '3.4' +services: + weaviate: + command: + - --host + - 0.0.0.0 + - --port + - '8080' + - --scheme + - http + image: semitechnologies/weaviate:1.18.0 + 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' + LOG_LEVEL: debug + AUTOSCHEMA_ENABLED: 'false' +... \ No newline at end of file diff --git a/tests/datastore/providers/weaviate/test_weaviate_datastore.py b/tests/datastore/providers/weaviate/test_weaviate_datastore.py new file mode 100644 index 000000000..300eb4849 --- /dev/null +++ b/tests/datastore/providers/weaviate/test_weaviate_datastore.py @@ -0,0 +1,538 @@ +import logging +import os + +import pytest +import weaviate +from _pytest.logging import LogCaptureFixture +from fastapi.testclient import TestClient +from loguru import logger +from weaviate import Client + +from datastore.providers.weaviate_datastore import ( + SCHEMA, + WeaviateDataStore, + extract_schema_properties, +) +from models.models import DocumentMetadataFilter, Source +from server.main import app + +BEARER_TOKEN = os.getenv("BEARER_TOKEN") + +client = TestClient(app) +client.headers["Authorization"] = f"Bearer {BEARER_TOKEN}" + + +@pytest.fixture +def weaviate_client(): + host = os.getenv("WEAVIATE_HOST", "http://localhost") + port = os.getenv("WEAVIATE_PORT", "8080") + client = Client(f"{host}:{port}") + + yield client + + client.schema.delete_all() + + +@pytest.fixture +def test_db(weaviate_client, documents): + weaviate_client.schema.delete_all() + weaviate_client.schema.create_class(SCHEMA) + + response = client.post("/upsert", json={"documents": documents}) + + if response.status_code != 200: + raise Exception( + f"Could not upsert to test client.\nStatus Code: {response.status_code}\nResponse:\n{response.json()}" + ) + + yield client + + +@pytest.fixture +def documents(): + documents = [] + + authors = ["Max Mustermann", "John Doe", "Jane Doe"] + texts = [ + "lorem ipsum dolor sit amet", + "consectetur adipiscing elit", + "sed do eiusmod tempor incididunt", + ] + ids = ["abc_123", "def_456", "ghi_789"] + sources = ["chat", "email", "email"] + created_at = [ + "1929-10-28T09:30:00-05:00", + "2009-01-03T16:39:57-08:00", + "2021-01-21T10:00:00-02:00", + ] + + for i in range(3): + documents.append( + { + "id": ids[i], + "text": texts[i], + "metadata": { + "source": sources[i], + "source_id": "5325", + "url": "http://example.com", + "created_at": created_at[i], + "author": authors[i], + }, + } + ) + + no_metadata_doc = { + "id": "jkl_012", + "text": "no metadata", + } + + documents.append(no_metadata_doc) + + partial_metadata_doc = { + "id": "mno_345", + "text": "partial metadata", + "metadata": { + "source": "file", + }, + } + + documents.append(partial_metadata_doc) + + yield documents + + +@pytest.fixture +def caplog(caplog: LogCaptureFixture): + handler_id = logger.add(caplog.handler, format="{message}") + yield caplog + logger.remove(handler_id) + + +@pytest.mark.parametrize( + "document_id", [("abc_123"), ("9a253e0b-d2df-5c2e-be6d-8e9b1f4ae345")] +) +def test_upsert(weaviate_client, document_id): + weaviate_client.schema.delete_all() + weaviate_client.schema.create_class(SCHEMA) + + text = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in ipsum eget dolor malesuada fermentum at ac massa. + Aliquam erat volutpat. Sed eu velit est. Morbi semper quam id urna fringilla lacinia. Vivamus sit amet velit id lorem + pretium molestie. Nulla tincidunt sapien eu nulla consequat, a lacinia justo facilisis. Maecenas euismod urna sapien, + sit amet tincidunt est dapibus ac. Sed in lorem in nunc tincidunt bibendum. Nullam vel urna vitae nulla iaculis rutrum. + Suspendisse varius, massa a dignissim vehicula, urna ligula tincidunt orci, id fringilla velit tellus eu metus. Sed + vestibulum, nisl in malesuada tempor, nisi turpis facilisis nibh, nec dictum velit velit vel ex. Donec euismod, + leo ut sollicitudin tempor, dolor augue blandit nunc, eu lacinia ipsum turpis vitae nulla. Aenean bibendum + tincidunt magna in pulvinar. Sed tincidunt vel nisi ac maximus. + """ + source = "email" + source_id = "5325" + url = "http://example.com" + created_at = "2022-12-16T08:00:00+01:00" + author = "Max Mustermann" + + documents = { + "documents": [ + { + "id": document_id, + "text": text, + "metadata": { + "source": source, + "source_id": source_id, + "url": url, + "created_at": created_at, + "author": author, + }, + } + ] + } + + response = client.post("/upsert", json=documents) + + assert response.status_code == 200 + assert response.json() == {"ids": [document_id]} + + properties = [ + "chunk_id", + "document_id", + "source", + "source_id", + "url", + "created_at", + "author", + ] + + where_filter = { + "path": ["document_id"], + "operator": "Equal", + "valueString": document_id, + } + + weaviate_doc = ( + weaviate_client.query.get("OpenAIDocument", properties) + .with_additional("vector") + .with_where(where_filter) + .with_sort({"path": ["chunk_id"], "order": "asc"}) + .do() + ) + + weaviate_docs = weaviate_doc["data"]["Get"]["OpenAIDocument"] + + assert len(weaviate_docs) == 2 + + for i, weaviate_doc in enumerate(weaviate_docs): + assert weaviate_doc["chunk_id"] == f"{document_id}_{i}" + + assert weaviate_doc["document_id"] == document_id + + assert weaviate_doc["source"] == source + assert weaviate_doc["source_id"] == source_id + assert weaviate_doc["url"] == url + assert weaviate_doc["created_at"] == created_at + assert weaviate_doc["author"] == author + + assert weaviate_doc["_additional"]["vector"] + + +def test_upsert_no_metadata(weaviate_client): + weaviate_client.schema.delete_all() + weaviate_client.schema.create_class(SCHEMA) + + no_metadata_doc = { + "id": "jkl_012", + "text": "no metadata", + } + + metadata_properties = [ + "source", + "source_id", + "url", + "created_at", + "author", + ] + + response = client.post("/upsert", json={"documents": [no_metadata_doc]}) + + assert response.status_code == 200 + + weaviate_doc = weaviate_client.query.get("OpenAIDocument", metadata_properties).do() + + weaviate_doc = weaviate_doc["data"]["Get"]["OpenAIDocument"][0] + + for _, metadata_value in weaviate_doc.items(): + assert metadata_value is None + + +@pytest.mark.parametrize( + "test_document, expected_status_code", + [ + ({"id": "abc_123", "text": "some text"}, 200), + ({"id": "abc_123"}, 422), + ({"text": "some text"}, 200), + ], +) +def test_upsert_invalid_documents(weaviate_client, test_document, expected_status_code): + weaviate_client.schema.delete_all() + weaviate_client.schema.create_class(SCHEMA) + + response = client.post("/upsert", json={"documents": [test_document]}) + + assert response.status_code == expected_status_code + + +@pytest.mark.parametrize( + "query, expected_num_results", + [ + ({"query": "consectetur adipiscing", "top_k": 3}, 3), + ({"query": "consectetur adipiscing elit", "filter": {"source": "email"}}, 2), + ( + { + "query": "sed do eiusmod tempor", + "filter": { + "start_date": "2020-01-01T00:00:00Z", + "end_date": "2022-12-31T00:00:00Z", + }, + }, + 1, + ), + ( + { + "query": "some random query", + "filter": {"start_date": "2009-01-01T00:00:00Z"}, + "top_k": 3, + }, + 2, + ), + ( + { + "query": "another random query", + "filter": {"end_date": "1929-12-31T00:00:00Z"}, + "top_k": 3, + }, + 1, + ), + ], +) +def test_query(test_db, query, expected_num_results): + queries = {"queries": [query]} + + response = client.post("/query", json=queries) + assert response.status_code == 200 + + num_docs = response.json()["results"][0]["results"] + assert len(num_docs) == expected_num_results + + +def test_delete(test_db, weaviate_client, caplog): + caplog.set_level(logging.DEBUG) + + delete_request = {"ids": ["def_456"]} + + response = client.request(method="delete", url="/delete", json=delete_request) + assert response.status_code == 200 + assert response.json()["success"] + assert weaviate_client.data_object.get()["totalResults"] == 4 + + client.request(method="delete", url="/delete", json=delete_request) + assert "Failed to delete" in caplog.text + caplog.clear() + + delete_request = {"filter": {"source": "email"}} + + response = client.request(method="delete", url="/delete", json=delete_request) + assert response.status_code == 200 + assert response.json()["success"] + assert weaviate_client.data_object.get()["totalResults"] == 3 + + client.request(method="delete", url="/delete", json=delete_request) + assert "Failed to delete" in caplog.text + + delete_request = {"delete_all": True} + + response = client.request(method="delete", url="/delete", json=delete_request) + assert response.status_code == 200 + assert response.json()["success"] + assert not weaviate_client.data_object.get()["objects"] + + +def test_build_auth_credentials(monkeypatch): + # Test when WEAVIATE_URL ends with weaviate.network and WEAVIATE_API_KEY is set + with monkeypatch.context() as m: + m.setenv("WEAVIATE_URL", "https://example.weaviate.network") + m.setenv("WEAVIATE_API_KEY", "your_api_key") + auth_credentials = WeaviateDataStore._build_auth_credentials() + assert auth_credentials is not None + assert isinstance(auth_credentials, weaviate.auth.AuthApiKey) + assert auth_credentials.api_key == "your_api_key" + + # Test when WEAVIATE_URL ends with weaviate.network and WEAVIATE_API_KEY is not set + with monkeypatch.context() as m: + m.setenv("WEAVIATE_URL", "https://example.weaviate.network") + m.delenv("WEAVIATE_API_KEY", raising=False) + with pytest.raises( + ValueError, match="WEAVIATE_API_KEY environment variable is not set" + ): + WeaviateDataStore._build_auth_credentials() + + # Test when WEAVIATE_URL does not end with weaviate.network + with monkeypatch.context() as m: + m.setenv("WEAVIATE_URL", "https://example.notweaviate.network") + m.setenv("WEAVIATE_API_KEY", "your_api_key") + auth_credentials = WeaviateDataStore._build_auth_credentials() + assert auth_credentials is None + + # Test when WEAVIATE_URL is not set + with monkeypatch.context() as m: + m.delenv("WEAVIATE_URL", raising=False) + m.setenv("WEAVIATE_API_KEY", "your_api_key") + auth_credentials = WeaviateDataStore._build_auth_credentials() + assert auth_credentials is None + + +def test_extract_schema_properties(): + class_schema = { + "class": "Question", + "description": "Information from a Jeopardy! question", + "properties": [ + { + "dataType": ["text"], + "description": "The question", + "name": "question", + }, + { + "dataType": ["text"], + "description": "The answer", + "name": "answer", + }, + { + "dataType": ["text"], + "description": "The category", + "name": "category", + }, + ], + "vectorizer": "text2vec-openai", + } + results = extract_schema_properties(class_schema) + assert results == {"question", "answer", "category"} + + +def test_reuse_schema(weaviate_client, caplog): + caplog.set_level(logging.DEBUG) + + weaviate_client.schema.delete_all() + + WeaviateDataStore() + assert "Creating index" in caplog.text + + WeaviateDataStore() + assert "Will reuse this schema" in caplog.text + + +def test_build_date_filters(): + filter = DocumentMetadataFilter( + document_id=None, + source=None, + source_id=None, + author=None, + start_date="2020-01-01T00:00:00Z", + end_date="2022-12-31T00:00:00Z", + ) + actual_result = WeaviateDataStore.build_filters(filter) + expected_result = { + "operator": "And", + "operands": [ + { + "path": ["created_at"], + "operator": "GreaterThanEqual", + "valueDate": "2020-01-01T00:00:00Z", + }, + { + "path": ["created_at"], + "operator": "LessThanEqual", + "valueDate": "2022-12-31T00:00:00Z", + }, + ], + } + + assert actual_result == expected_result + + +@pytest.mark.parametrize( + "test_input, expected_result", + [ + ("abc_123", False), + ("b2e4133c-c956-5684-bbf5-584e50ec3647", True), # version 5 + ("f6179953-11d8-4ee0-9af8-e51e00dbf727", True), # version 4 + ("16fe8165-3c08-348f-a015-a8bb31e26b5c", True), # version 3 + ("bda85f97-be72-11ed-9291-00000000000a", False), # version 1 + ], +) +def test_is_valid_weaviate_id(test_input, expected_result): + actual_result = WeaviateDataStore._is_valid_weaviate_id(test_input) + assert actual_result == expected_result + + +def test_upsert_same_docid(test_db, weaviate_client): + def get_doc_by_document_id(document_id): + properties = [ + "chunk_id", + "document_id", + "source", + "source_id", + "url", + "created_at", + "author", + ] + where_filter = { + "path": ["document_id"], + "operator": "Equal", + "valueString": document_id, + } + + results = ( + weaviate_client.query.get("OpenAIDocument", properties) + .with_additional("id") + .with_where(where_filter) + .with_sort({"path": ["chunk_id"], "order": "asc"}) + .do() + ) + + return results["data"]["Get"]["OpenAIDocument"] + + def build_upsert_payload(document): + return {"documents": [document]} + + # upsert a new document + # this is a document that has 2 chunks and + # the source is email + doc_id = "abc_123" + text = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in ipsum eget dolor malesuada fermentum at ac massa. + Aliquam erat volutpat. Sed eu velit est. Morbi semper quam id urna fringilla lacinia. Vivamus sit amet velit id lorem + pretium molestie. Nulla tincidunt sapien eu nulla consequat, a lacinia justo facilisis. Maecenas euismod urna sapien, + sit amet tincidunt est dapibus ac. Sed in lorem in nunc tincidunt bibendum. Nullam vel urna vitae nulla iaculis rutrum. + Suspendisse varius, massa a dignissim vehicula, urna ligula tincidunt orci, id fringilla velit tellus eu metus. Sed + vestibulum, nisl in malesuada tempor, nisi turpis facilisis nibh, nec dictum velit velit vel ex. Donec euismod, + leo ut sollicitudin tempor, dolor augue blandit nunc, eu lacinia ipsum turpis vitae nulla. Aenean bibendum + tincidunt magna in pulvinar. Sed tincidunt vel nisi ac maximus. + """ + + document = { + "id": doc_id, + "text": text, + "metadata": {"source": Source.email}, + } + + response = client.post("/upsert", json=build_upsert_payload(document)) + assert response.status_code == 200 + + weaviate_doc = get_doc_by_document_id(doc_id) + assert len(weaviate_doc) == 2 + for chunk in weaviate_doc: + assert chunk["source"] == Source.email + + # now update the source to file + # user still has to specify the text + # because test is a required field + document["metadata"]["source"] = Source.file + response = client.post("/upsert", json=build_upsert_payload(document)) + assert response.status_code == 200 + + weaviate_doc = get_doc_by_document_id(doc_id) + assert len(weaviate_doc) == 2 + for chunk in weaviate_doc: + assert chunk["source"] == "file" + + # now update the text so that it is only 1 chunk + # user does not need to specify metadata + # since it is optional + document["text"] = "This is a short text" + document.pop("metadata") + + response = client.post("/upsert", json=build_upsert_payload(document)) + assert response.status_code == 200 + weaviate_doc = get_doc_by_document_id(doc_id) + assert len(weaviate_doc) == 1 + + # TODO: Implement update function + # but the source should still be file + # but it is None right now because an + # update function is out of scope + assert weaviate_doc[0]["source"] is None + + +@pytest.mark.parametrize( + "url, expected_result", + [ + ("https://example.weaviate.network", True), + ("https://example.weaviate.network/", True), + ("https://example.weaviate.cloud", True), + ("https://example.weaviate.cloud/", True), + ("https://example.notweaviate.network", False), + ("https://weaviate.network.example.com", False), + ("https://example.weaviate.network/somepage", False), + ("", False), + ], +) +def test_is_wcs_domain(url, expected_result): + assert WeaviateDataStore._is_wcs_domain(url) == expected_result diff --git a/tests/datastore/providers/zilliz/test_zilliz_datastore.py b/tests/datastore/providers/zilliz/test_zilliz_datastore.py new file mode 100644 index 000000000..f790797a8 --- /dev/null +++ b/tests/datastore/providers/zilliz/test_zilliz_datastore.py @@ -0,0 +1,29 @@ +# from pathlib import Path +# from dotenv import find_dotenv, load_dotenv +# env_path = Path(".") / "zilliz.env" +# load_dotenv(dotenv_path=env_path, verbose=True) + +import pytest + +from datastore.providers.zilliz_datastore import ( + ZillizDataStore, +) + +from datastore.providers.milvus_datastore import ( + EMBEDDING_FIELD, +) + +# Note: Only do basic test here, the ZillizDataStore is derived from MilvusDataStore. + +@pytest.fixture +def zilliz_datastore(): + return ZillizDataStore() + + +@pytest.mark.asyncio +async def test_zilliz(zilliz_datastore): + assert True == zilliz_datastore.col.has_index() + index_list = [x.to_dict() for x in zilliz_datastore.col.indexes] + for index in index_list: + if index['index_name'] == EMBEDDING_FIELD: + assert 'AUTOINDEX' == index['index_param']['index_type'] \ No newline at end of file From 3be119b225e0d8028aea4aeec041397c2062fd01 Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Tue, 29 Aug 2023 12:40:07 +0100 Subject: [PATCH 03/28] KXI-28991 newclientversion --- .../kdbai_datastore.cpython-310.pyc | Bin 7184 -> 7549 bytes datastore/providers/kdbai_datastore.py | 92 +++++++----------- server/__pycache__/main.cpython-310.pyc | Bin 4027 -> 4027 bytes 3 files changed, 33 insertions(+), 59 deletions(-) diff --git a/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc b/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc index ee9a8147351c0c88d7eb81330dc97c22191cbdcd..b20ae18473c6bf17bb451802821ebbcf43e102f0 100644 GIT binary patch delta 2647 zcmaJ@TWl298J;scGkfvgY_Bn31B)Svhf8e(A<3HJCdN<-gcegM>p07>=NON@JG(hE z8?TpjH-WxImV!nhw_dz2iFl0sp65t?=~EP)stHnWu7OGHe&FBAm z=A7^U|1aX~ut+i06uhfXPUnC|$ELU*wKTcP}6N@f*v=jL1L$Haf6eKjpKkJUZVLo3Bv znK@p;rXuQAYP`r$RN*lKRfKB1Bw|I*ERWHGrHiSY1-R~>+9P3VWkWmpj+tR zdWddaSFcC$c$h>@5p~|eHDPD5*E26CFL}|pl)JB?) zH1*Gw->I0|)Nc|BzF+GrWJNLe_>J&FOGJu`HD?)0!H0oZQx%$Hm6#ooiN>EYt z>><7tQp^za1+3o^MwxlsE((p>W!F^sICw?RyR7I{_-Ti-x=BR1SSi)Yj@w90V{^cI zSgubL*{7PfW5K4*-Qbo(=MKGmbbe|iJF=E#R&g=w*`;iK zG8^=CC*<(>|A}bHDd?;T?ca%?7=Kp6lgWUDi4&9Afad4D<4FN>qxH#&mk%E`_l(x} zNnvV&na0{ZypsHAWSI2&FGlvapbkY(#DjMgB+bHj{5K#`=#o95F4qNlN2pa8VO!ED zqBHd(t9rmcSFw;f=_ANkomqgMaZ!gAY*)Z}vyu3-w?N2hBX@ z|2}@4T=4%A-#avfR(vs^1rV`gCEN9im2&m?pZwv(jWKlHRrzIf5-*7ChVwj_zk}yr zc+`x-ulV`I@Hn3X%_R5WhU%>SR#*Dp+&`oJZND#hhfMi*lRq}(CP(~#B!}iNflsJT zRp=Jy)++xQ>d_O>q9-}bC&ycmzkx7`FoSRgK#+?bd( zvs}D=fT>EgupBUjMGWW)HS8)c`}Z@a`Ybdi5pbVo9A0p8VAmC-MW!r!uR delta 2274 zcmbVM-ES0C6rVdYJNwag`$1dU?iLm(w9{@sKr{tQp|<72@}aa;UC_y}_m)oCFYnCS zcCA*ZQ650Sn`k0vT1hk{@?szT1N6lweY(*H-_!?8G#W!B@t!;F789P>WPfwc?|j^I z&p9&>_FwOh=BuhAiugVIf|nzDkr8% zLb3@5n;O@1c9!rEwmo}dzCd^dCT^NK1<%RngpyAevn1z<45ey_Tqi^@*F7@lm1@cf z+uZ~(;;4L)rb(%BVo^l+N+Lg%@E~5C!^1uYNvj}w%|)ctiZoM-KEw%~N79to9>JFF zaa|-JrRHH^M1_!#K<@RrxM3H)={zk}kBHJMp!S5%u=ljDI_YMyVzd#USpZiZOq)P! z0f+&mpU>lY+OfK%2T`*w7+A|;@prEXSU?MkrIb3^?LhY#go8^6DGTay0Ebq5D>)gqzu>|VGju5;Zb znJL;UF2I8>l|SXbm+>k?dVivXii4Tb_WD1<6esIC&#Al+E~A@Y`1vC+6% zW<>|l2>UeJ7V8i(bOc~j0FMl09M?vc$73p=csCh28P*F$R)sRM09G;Fz!3 z&DvQs$u`x^?ttx+D`;xe0{JvRNPrpekDO$8>k{>{2OEtzBOGF@Ki7SXj6n$KTfJ02 zhENy#u3;NWvfmrFEy}jYQ9TdY5ZCQF$CZn3>NF`h9&ponO8nPj5}Z^D*?5o=x0vx< zvxOT|PR1j2txYbmX?of(^sMlt=Kx-W7{hiw_>=^^e8IX%57vVPM(p=dD>(%^z-~7l zsT&6}3IKaf3dsVKXFG`O#f^|uYz0-mCJca?4Ve%<4vc!<;-1hnP2x4@iIo5= zoF4XVQ_{EsekFFl>E2n`EP5FLc8crM#Ks#P@pmjOEbD{zL&5(#z{UoZ%i{(n8RC(5 z*>KDBBD}iP1UL+!0|Wrz+ePyL20#UX1^`<_s{v&D-v_Bm0DS($&VB%Txls>wrAHVp ziN6a23n^+qf1qk1^?@3R{Jp)O?TPhvfs6Sh*JoVukx}z5y(S256zm+fUHUR8fm|_L zn5Spi)!668KEcp_)*tWf Date: Wed, 30 Aug 2023 11:14:54 +0100 Subject: [PATCH 04/28] KXI-28991 working-upsert --- .../kdbai_datastore.cpython-310.pyc | Bin 7549 -> 7113 bytes datastore/providers/kdbai_datastore.py | 151 +++++++++--------- 2 files changed, 78 insertions(+), 73 deletions(-) diff --git a/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc b/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc index b20ae18473c6bf17bb451802821ebbcf43e102f0..8c17e7eb68c9ee5567480f12e6c991a8cf73dcce 100644 GIT binary patch delta 2611 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 diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index 122232080..44042573a 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -23,29 +23,30 @@ ) try: - ## New for kdbai_client - import kdbai_client as kdbai - print('KDBAI-CLIENT version: ' + kdbai.__version__) - ## + import pykx as kx + print('PyKX version: ' + kx.__version__) except ImportError: raise ValueError( - "Could not import kdbai python package. " + "Could not import pykx python package. " "Please add it to the dependencies." ) try: - import pykx as kx - print('PyKX version: ' + kx.__version__) + ## New for kdbai_client + import kdbai_client as kdbai + print('KDBAI-CLIENT version: ' + kdbai.__version__) + ## except ImportError: raise ValueError( - "Could not import pykx python package. " + "Could not import kdbai python package. " "Please add it to the dependencies." ) + # DEFAULT_EMBEDDING_MODEL = 'text-embedding-ada-002' # The name of the table @@ -72,15 +73,51 @@ KDBAI_VECTOR_COL_NAME = "vecs" -table = pd.DataFrame({'text': pd.Series(dtype='str'), - 'document_id': pd.Series(dtype='str'), - 'source_id': pd.Series(dtype='str'), - 'id': pd.Series(dtype='str'), - 'source': pd.Series(dtype='str'), - 'url': pd.Series(dtype='str'), - 'created_at': pd.Series(dtype='str'), - 'body': pd.Series(dtype='str'), - 'vecs': pd.Series(dtype='float32')}) +schema = dict( + columns=[ + dict( + name='vecs', + vectorIndex= + dict( + type='flat', + metric='L2', + dims=DEFAULT_DIM + ) + ), + dict( + name='source', + pytype='bytes' + ), + dict( + name='source_id', + pytype='str' + ), + dict( + name='url', + pytype='bytes' + ), + dict( + name='created_at', + pytype='datetime64[ns]' + ), + dict( + name='author', + pytype='bytes' + ), + dict( + name='document_id', + pytype='str' + ), + dict( + name='text', + pytype='bytes' + ), + dict( + name='chunk_id', + pytype='str' + ) + ] + ) class KDBAIDataStore(DataStore): @@ -112,44 +149,23 @@ def __init__( print('Creating kdbai Session...') session = kdbai.Session(host='localhost', port=8082, protocol='http') print("Tables in current session:") - print(session.list()) - - #schema = {"type":"splayed","columns":[{"name":"time","type":"timespan"},{"name":"sym","type":"symbol","attrMem":"grouped"},{"name":"chunk_id","type":"symbol"},{"name":"document_id","type":"symbol"},{"name":"text","type":"string"},{"name":"source","type":"string"},{"name":"source_id","type":"symbol"},{"name":"url","type":"string"},{"name":"created_at","type":"timespan"},{"name":"author","type":"string"},{"name":"embeddings","type":"reals", "vectorIndex": {"type": "flat", "metric": "L2", "dims": 1536}}]} - - schema = dict( - columns=[ - dict(name='chunk_id', pytype='str'), - dict(name='document_id', pytype='str'), - dict(name='text', pytype='bytes'), - dict(name='source', pytype='bytes'), - dict(name='source_id', pytype='str'), - dict(name='url', pytype='bytes'), - dict(name='created_at', pytype='datetime64[ns]'), - dict(name='author', pytype='bytes'), - dict(name='embeddings', - vectorIndex=dict(type='flat', metric='L2', dims=8))] - ) + print(session.list()) # create a vector database table using the schema - print('Creating table:') - self._table = session.create_table('testingqueryfunc', schema) + print('Getting table:') + name = 'testingupsert1' + + try: + self._table = session.create_table(name, schema) + except: + self._table = session.table(name) + print('Session tables:') print(session.list()) print('Table schema:') print(self._table.schema()) - - print('Table query:') - print(self._table.query()) - - print('Inserting data:') - df = kx.q('{([] chunk_id:x?`8; document_id:x?`8; text:{rand[256]?" "} each til x; source:{rand[30]?" "} each til x; source_id:x?`8; url:{rand[100]?" "} each til x; created_at:x?1D; author:{rand[30]?" "} each til x; embeddings:(x;1536)#(x*1536)?1e)}', 10).pd() - self._table.insert(df) - - print('Table query:') - print(self._table.query()) - except Exception as e: logger.error(f"Error in creating table: {e}") @@ -173,9 +189,8 @@ async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: # Initialize a list of ids to return try: - global table doc_ids: List[str] = [] - + # Initialize a list of vectors to upsert vecs = [] # Loop through the dict items @@ -212,42 +227,35 @@ async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: for batch in batches: - # generates an embedding vector of length batch - embeddings = np.array([t[0] for t in batch]) + # generates an embedding vector for each item in batch + embeddings = np.array([t[0] for t in batch]) # vec[0] + print("Shape of embeddings vector: ", embeddings.shape) df = pd.DataFrame(dict(vecs=list(embeddings))) - new_meta_df = pd.DataFrame([t[1] for t in batch]) + + # extracts each metadata item in batch to DataFrame + new_meta_df = pd.DataFrame([t[1] for t in batch]) # vec[1] + + print("DataFrame columns: ", new_meta_df.columns) for col in new_meta_df.columns: - df[col]=new_meta_df[col] + df[col] = new_meta_df[col] try: logger.info(f"Upserting batch of size {len(batch[0])}") - - # call insert() function from kdbai.Index() instance - #self._index.insert(embeddings) - - # NEW KDBAI-CLIENT requires pd.DataFrame input - # INSERT EMBEDDINGS + METADATA AT SAME TIME - - # make dataframe with schema - + + print("Inserting DataFrame:") + print(df) - self._table.insert(pd.DataFrame(embeddings).T) + self._table.insert(df) logger.info(f"Upserted batch successfully") - table = table.append(df) except Exception as e: logger.error(f"Failed to insert batch records, error: {e}") raise e return doc_ids - # try: - # df = kx.q('{([] time:0Nn; sym:`; id: `$string x?0Ng; tag: x?`3; text: {rand[256]?" "} each til x; embeddings: (x;1536)#(x*1536)?1e)}', 10).pd() - # self._table.insert(df) - # print("inserted to the table!") - # self._table.query() except Exception as e: logger.error("Insert to collection failed, error: {}".format(e)) @@ -371,15 +379,12 @@ async def delete( # If deleting all, drop collection try: - global table if delete_all: - #self._index.drop() - # NEW KDBAI-CLIENT self._table.drop() - table = table.head(0) + # table = table.head(0) else: logger.error("Functionality is not implemented yet") From bb4994a9a48c1ea38c2f4e59ff1cf4e37626f070 Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Wed, 30 Aug 2023 14:16:19 +0200 Subject: [PATCH 05/28] Remove __pycache__ dirs from Git. --- datastore/__pycache__/__init__.cpython-310.pyc | Bin 153 -> 0 bytes datastore/__pycache__/datastore.cpython-310.pyc | Bin 3346 -> 0 bytes datastore/__pycache__/factory.cpython-310.pyc | Bin 2183 -> 0 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 163 -> 0 bytes .../__pycache__/kdbai_datastore.cpython-311.pyc | Bin 10860 -> 0 bytes .../pinecone_datastore.cpython-310.pyc | Bin 6756 -> 0 bytes models/__pycache__/api.cpython-310.pyc | Bin 1469 -> 0 bytes models/__pycache__/models.cpython-310.pyc | Bin 2845 -> 0 bytes server/__pycache__/main.cpython-310.pyc | Bin 4027 -> 0 bytes services/__pycache__/__init__.cpython-310.pyc | Bin 152 -> 0 bytes services/__pycache__/chunks.cpython-310.pyc | Bin 4338 -> 0 bytes services/__pycache__/date.cpython-310.pyc | Bin 867 -> 0 bytes services/__pycache__/file.cpython-310.pyc | Bin 3153 -> 0 bytes services/__pycache__/openai.cpython-310.pyc | Bin 2132 -> 0 bytes 14 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 datastore/__pycache__/__init__.cpython-310.pyc delete mode 100644 datastore/__pycache__/datastore.cpython-310.pyc delete mode 100644 datastore/__pycache__/factory.cpython-310.pyc delete mode 100644 datastore/providers/__pycache__/__init__.cpython-310.pyc delete mode 100644 datastore/providers/__pycache__/kdbai_datastore.cpython-311.pyc delete mode 100644 datastore/providers/__pycache__/pinecone_datastore.cpython-310.pyc delete mode 100644 models/__pycache__/api.cpython-310.pyc delete mode 100644 models/__pycache__/models.cpython-310.pyc delete mode 100644 server/__pycache__/main.cpython-310.pyc delete mode 100644 services/__pycache__/__init__.cpython-310.pyc delete mode 100644 services/__pycache__/chunks.cpython-310.pyc delete mode 100644 services/__pycache__/date.cpython-310.pyc delete mode 100644 services/__pycache__/file.cpython-310.pyc delete mode 100644 services/__pycache__/openai.cpython-310.pyc diff --git a/datastore/__pycache__/__init__.cpython-310.pyc b/datastore/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 9c3183cc4c5b839e1d9357162bba72c17e77716b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmd1j<>g`kf|WIoQ$X}%5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HGenx(7s(x}o zesNxEk$!SUVo7>IiEdG9Nl|8MSz?ZEK~8CUW}bdZVo73gNq$kPetdjpUS>&ryk0@& WEe@O9{FKt1R6CHV#Y{kgg#iEy)g+t% diff --git a/datastore/__pycache__/datastore.cpython-310.pyc b/datastore/__pycache__/datastore.cpython-310.pyc deleted file mode 100644 index 258b98868790b86c79f8fd1295616cfd5d41aae6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3346 zcmcgu&2JmW6`z@1E|(NZQ6K(@o21*?LCivyb7>ESW2Cj?CPky7c7Xzm28-3sNLqV8 zn3<()5fqSALX%4Z^wP5feMP&m}^>#?IpBLgy_g>Je0&aGH^vhBRj(qu6Jele?jtH^N5lg`SZ) zSu$AtTW z9y#F}ckYov>l-+o448I)_3K-@7jLUd#z~cnYOmx2N4vMvq|)y1QdMdH_roeJi#XdF zc-p^RCZk*wmG0K9TYID8fj(b%-xF2L<0`(BW|fe-@rRL+2YSi;-4$w-ReIHQ{*+dG zZ|B>B^R(C>kmu!`m?4osRWjp39eb z=hzLGVLguZpBwA)o>{jdS}lq{evU7L2Ig#-*@yNj{I9_OnpwHFu{0m6G#DaDp<)u1TdH?Txi`9KtrO2ZBo0_#f9PXaj-aStLiG`?$bI@T z*`b_rcI;2+ZE{3EBkuw@?+{8VHlY)C#15TL$YW>Xd`|5MsN%-pm!us`zdyzggbLCk zh=UBABPe%*nRY>3a2QfTRw}6WL=K&*#8!X~u^lV1Ios$?Dq%SnnW$jHILpjD@d!2r zcL?@H0>-Q0AvlTMVd@w`%7d%vPEd$MC>6_t4cKHT3a)~(Ff;AafNu{ruwN{y1j`=6 zJfY@_+%@=}VGo?NFf9QTW*>u=2W1V4x(d}UnUMGUhjc>k6UjaSuo2SxK3~Ns)rdtYzXKffb}Uue7L5qN01C2{YtKq#3yy$^Z1WB6*NdM}?JAM&JR#q{ zd3~?U#r0%ZszS)?$zELT4y$Y688Q|7advH(jds)GI^KdppPIKehX=ZS1FteE^Wn{x z(V+8Cd4x4x%Ki<7y3{>kj{DR*8DE*X<>qLJ7rl8SE0Z`=H=$8)vNdpZGgb#hl9t-r zjo}ic?82tH8QE0>SN;h4vX9jYj(C>u5*3h_uzJOa?fg|}E1b+ebX#o-s{N;Z((d-z zxPMw9`BRvd;04tmw(;`5gz_)EHDtqI=zxwto_XULZhhLl1FPZx<>cSfx8N$*w#w?= ze3%K0t%AQTWhn>DqJ$P%U<^74jQj~y8&DMT98hVFSLR4eQP#~5Aoiw0JqJev7T_X; zL*0PtBO4Tm4GM>>A`lAbp~D>r6{G^6o;XJg1ID2{A&=R_HQ~X1hk!pf#(#Ygh*Jd& zXx7Vt>kuVu(1P|Xir~xxkYj?F(ms!?WDkQu?edFPpc3%o7xB{p)9#^-=sbp>4a-l< zL<1<0v0)Ads4v1aiCjJn^{XJmAga)jR>}DC9B8xlEDAgqEl`st6r;`0pkcIG`7=AD zh&HDwVE>qYPQHNLHDM|Jf__G)@q+2rEcaQJne4z8+U1a;2hM`p0}!93`LT)~NI->b= zC<;$wANCqP^_b7RXMK0Pdcaq&5*5~OGSVY`lAH5C7tL2*~)kF8i)0~v+sFn) z-Ge8ikY?X%hBLUPc*`R3g|C zsbb=*#HXc%NBlG{Anznzr^(0K-7d>aqMi%7&m;6Q3}9+gzktdojJYQsWwx;PGj{0; zz2vjr%anP{VVGv0wi$coIqbil%bv1E|2v6$4A!+1ZzmEtVYJj(r+K>-ZhI?)(oD0!jq{ diff --git a/datastore/__pycache__/factory.cpython-310.pyc b/datastore/__pycache__/factory.cpython-310.pyc deleted file mode 100644 index 4cf3f6c06aa6de3dac31c7596f03dd43d6230945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2183 zcmZ{l&yU+g6vsWbT;RQl<4jT3k|%HG^PQPD@4az?YPF=n^XQMi z=&wah`x86rV?gH}c*C2}P>m9(pSRuTzuezA=vts&}=9^*3m>21$ws zPULi>K(PCXC0H~Teh<<7se@s{`wP6`&qUL{CXx09d8SkHoW$B0Y%(Tc^#kpkoPm() zk9DyFTN~8mhG)j$#u<64b&=(Oy)2omfxRJFf#ST1E%U?-B*c-5=L7BDMibzqTXE4=Ql#Cc%(XRFV(yKtiS zXa25&=3Hvl_?ovK7eG@;=dT0%R056oKam$SD>={axA3$|1>d?syK6 z+J|T?Kw;$itQYtU*y@ASR`3(%Ok5|D__NerV9Rs)WE|p-A4y9=Q@YBfc(Gw7?chcU$orR>zxD$dR^JDW+9aso+kLiiy!ZNjc2X{Jm zGceu#)CVU=fruEjC#(mT)uwQ3(d*mxwBNFi#HkJWu!FuG4Vm2!I1iq<{@}JPbJ(!4- zMY@90r6-f&Q4uuFrqn;GAon)N}EFpoVAu#0v zlPNGw0y7{mssckLFa!dRCeUGlJ_s9{A2snR{QUD~dl-1E-GhMmOtgDLCmM{RTksbt zTsCp|tq~s&T)&-d-|jnjHBVck)1(TQW8roV)(a^#`d1ZFA-Z0I)|$7vVyoj|*XEl4 zjc0Rl+^{6oiB3wy{8zjV8#T;iJ#(y;SwaUU_OU^gJgCyV24hL#Eia&B&fdoVg%Gc9 JMJtds<3Asbhxz~j diff --git a/datastore/providers/__pycache__/__init__.cpython-310.pyc b/datastore/providers/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index fbf9a170f3a8e0c24ef020a578fa6c421a39bfec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmd1j<>g`kf|WIoQ$X}%5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HUenx(7s(x}o zesNxEk$!SUVo7>IiEdG9Nl|8MSz?ZEK~8CUW}bdZVo73gNq$kPenC-wS!POVQL%n} gd}dx|NqoFsLFFwDo80`A(wtN~kom<-K!Sw<0Kiiyvj6}9 diff --git a/datastore/providers/__pycache__/kdbai_datastore.cpython-311.pyc b/datastore/providers/__pycache__/kdbai_datastore.cpython-311.pyc deleted file mode 100644 index a080f7e0c977e2638f441019ac767f7bb0e6a9f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10860 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 CVh^7H diff --git a/datastore/providers/__pycache__/pinecone_datastore.cpython-310.pyc b/datastore/providers/__pycache__/pinecone_datastore.cpython-310.pyc deleted file mode 100644 index 95de97243da54fc14aa060e64877b544c1126c1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6756 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 UtMc=#TCUp24gWRUvFGhS0bmu{h5!Hn diff --git a/models/__pycache__/api.cpython-310.pyc b/models/__pycache__/api.cpython-310.pyc deleted file mode 100644 index 10d62a5beca9d776b4692edc78a978ea77d4ee95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1469 zcmai!OHUgy5PF0ABzV0$Y?>aG0| z{R{jhUpe*6t*6d-6F`U*N1pZPu{<-LnbdI{5g3<0u9)Z%a)oerxBz=F)o&1tFe*q% zQ(E@YUg@Mx>838l{hshjKlSa}5&beqgECA*Nl^ zSP0Ff@jka)&dtDnPPl4?o=_9+=ZYWIjEhOnxE~9pP4KDFMP21$hIii`4!|DF>lYw6 zNhu>~@04(dyIX{NjPAmFfLD%*PaDOhKH(QFhbu$2@J=01d=q3@m6trrOq6A1&02x$ zVU}IAx#%>q4;Cckg_v=c-}|rqP0&8Sv5&OUzS;-vZK*MuLa}jZsVxE}*JnK_IhqEr7g~0J z-82FoSoTm4CFz^^fD5kqq9l*yI$Ui0Z?-uOO$7A;+AJ4hGQ6KrJSqbewk)6F%BJrn zt{fDvKp6LHU5f`3jtzr{72Xn&b(+w1Dsgvp-2eap diff --git a/models/__pycache__/models.cpython-310.pyc b/models/__pycache__/models.cpython-310.pyc deleted file mode 100644 index d02e66d45638559136d23475a7b4a88f7f2424d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2845 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 diff --git a/services/__pycache__/__init__.cpython-310.pyc b/services/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 9ce1c00618bcfd356e9b7bf6f20225eadcd1fa04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152 zcmd1j<>g`kf|WIoQ$X}%5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!Huenx(7s(x}o zesNxEk$!SUVo7>IiEdG9Nl|8MSz?ZEK~8CUW}bd=YEfBca%!=De0*kJW=VX!UP0w8 V4x8Nkl+v73JCLEpOhAH#0RZD`Bsc&7 diff --git a/services/__pycache__/chunks.cpython-310.pyc b/services/__pycache__/chunks.cpython-310.pyc deleted file mode 100644 index 42a3b669e7910d02064bb4960b2bc3c3963eea39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4338 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 ZqwaeD){B`IRUu#cu{JTP7CEF3!#}@K@s|Jq diff --git a/services/__pycache__/file.cpython-310.pyc b/services/__pycache__/file.cpython-310.pyc deleted file mode 100644 index 224935a9af15ec3276a850d07c29a616032599e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3153 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 Date: Wed, 30 Aug 2023 14:20:32 +0200 Subject: [PATCH 06/28] Clean up repo and tweak pyproject.toml. --- .gitignore | 1 + ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier | 3 --- pyproject.toml | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) create mode 100644 .gitignore delete mode 100644 ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..bee8a64b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier b/ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier deleted file mode 100644 index 8de5cfaa3..000000000 --- a/ChatGPT_Retrieval_Plugin_QA.ipynb:Zone.Identifier +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=https://files.slack.com/files-pri/T0HLFPUJE-F05J0S9UA8P/download/chatgpt_retrieval_plugin_qa.ipynb?origin_team=T0HLFPUJE diff --git a/pyproject.toml b/pyproject.toml index 2f2404176..fd919a7f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,6 @@ authors = ["isafulf "] readme = "README.md" packages = [ {include = "server"}, - {include = "kdbai_client", from="/home/cposner/.local/lib/python3.10/site-packages/"}, ] [[tool.poetry.source]] @@ -45,6 +44,7 @@ psycopg2cffi = {version = "^2.9.0", optional = true} loguru = "^0.7.0" elasticsearch = "8.8.2" pykx="^1.6.3" +kdbai_client = { path = "../kdbai-python-client" } [tool.poetry.scripts] start = "server.main:start" From 30fead29858225fa4c10128fce24279ccde6b254 Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Wed, 30 Aug 2023 15:56:58 +0200 Subject: [PATCH 07/28] Clean up .pyc file and minor refactoring. --- .../__pycache__/kdbai_datastore.cpython-310.pyc | Bin 7113 -> 0 bytes datastore/providers/kdbai_datastore.py | 3 +-- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc diff --git a/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc b/datastore/providers/__pycache__/kdbai_datastore.cpython-310.pyc deleted file mode 100644 index 8c17e7eb68c9ee5567480f12e6c991a8cf73dcce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7113 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 diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index 44042573a..1e1a41bde 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -238,8 +238,7 @@ async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: print("DataFrame columns: ", new_meta_df.columns) - for col in new_meta_df.columns: - df[col] = new_meta_df[col] + df = pd.concat([df, new_meta_df], axis=1) try: logger.info(f"Upserting batch of size {len(batch[0])}") From 437213b4b426bb6f619cd60f0918f6c64e8b60d0 Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Thu, 31 Aug 2023 11:19:04 +0200 Subject: [PATCH 08/28] Get the ChatGPT Plugin working end to end with the last KDBAI Python client. --- ChatGPT_Retrieval_Plugin_QA.ipynb | 459 ------------------------- datastore/providers/kdbai_datastore.py | 372 ++++---------------- 2 files changed, 61 insertions(+), 770 deletions(-) delete mode 100644 ChatGPT_Retrieval_Plugin_QA.ipynb diff --git a/ChatGPT_Retrieval_Plugin_QA.ipynb b/ChatGPT_Retrieval_Plugin_QA.ipynb deleted file mode 100644 index b0de93bc7..000000000 --- a/ChatGPT_Retrieval_Plugin_QA.ipynb +++ /dev/null @@ -1,459 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# KDBAI for Q&A with ChatGPT Retrieval Plugin" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. Install Python 3.10 if not already installed.\n", - "\n", - "2. Clone the `retrieval-app` repository:\n", - "\n", - "```\n", - "git clone git@github.com:openai/retrieval-app.git\n", - "```\n", - "\n", - "3. Navigate to the app directory:\n", - "\n", - "```\n", - "cd /path/to/retrieval-app\n", - "```\n", - "\n", - "4. Install `poetry`:\n", - "\n", - "```\n", - "pip install poetry\n", - "```\n", - "\n", - "5. Create a new virtual environment:\n", - "\n", - "```\n", - "poetry env use python3.10\n", - "```\n", - "\n", - "6. Install the `retrieval-app` dependencies:\n", - "\n", - " Before installing the dependencies with poetry, we will need to add pyKX and a local KDBAI python package as a dependence in the `pyproject.toml` file. This can be done by pointing the KDBAI package under `[tool.poetry.dependencies]` by adding the following lines.\n", - "\n", - " - __pykx = \"^1.6.0\"__\n", - " - __kdbai = { path = \"path/to/kdbaiPackage.tar.gz\", develop = false }__\n", - "\n", - "```\n", - "poetry install\n", - "```\n", - "\n", - "7. Set app environment variables:\n", - "\n", - "* `BEARER_TOKEN`: Secret token used by the app to authorize incoming requests. The token can be generated using [jwt.io](https://jwt.io/).\n", - "\n", - "* `OPENAI_API_KEY`: The OpenAI API key used for generating embeddings with the `text-embedding-ada-002` model. [Get an API key here](https://platform.openai.com/account/api-keys)!\n", - "\n", - "8. Set `KDBAI`-specific environment variables:\n", - "\n", - "* `DATASTORE`: set to `kdbai`.\n", - "\n", - "8. Run the app with:\n", - "\n", - "```\n", - "poetry run start\n", - "```\n", - "When the application is up and running a FastAPI server exposes the ChatGPT plugin's endpoints for `upserting`, `querying`, and `deleting` documents.\n", - "\n", - "During the start up of the application `KDBAI` initiates a new HNSW index named `openaiEmbeddings` with default parameters {\"efConstruction\": 8, \"efSearch\": 8, \"M\": 32}" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/alexg/Applications/miniforge3/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" - ] - } - ], - "source": [ - "import os\n", - "import requests\n", - "from tqdm.auto import tqdm\n", - "from datasets import load_dataset\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# If the bearer token is not set as an environment variable, you can set it manually here\n", - "BEARER_TOKEN = os.environ.get(\"BEARER_TOKEN\")\n", - "headers = {\"Authorization\": f\"Bearer {BEARER_TOKEN}\"}" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Load Dataset from Hugging Face\n", - "\n", - "The Adversarial_QA dataset is chosen for this demo.\n", - "The adversarial human annotation paradigm ensures that these datasets consist of questions that current state-of-the-art models find challenging." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Found cached dataset adversarial_qa (/Users/alexg/.cache/huggingface/datasets/adversarial_qa/adversarialQA/1.0.0/92356be07b087c5c6a543138757828b8d61ca34de8a87807d40bbc0e6c68f04b)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of unique contexts: 2648\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
idtitlecontextquestionanswersmetadata
07ba1e8f4261d3170fcf42e84a81dd749116fae95BrainAnother approach to brain function is to exami...What sare the benifts of the blood brain barrir?{'text': ['isolated from the bloodstream'], 'a...{'split': 'train', 'model_in_the_loop': 'Combi...
12936a8460bfffe437b54cf3ec1e825a3b7b5627a1BrainMotor systems are areas of the brain that are ...What do you think with?{'text': ['brain'], 'answer_start': [467]}{'split': 'train', 'model_in_the_loop': 'Combi...
24e40737d487964dbcd26a223f2799cf56390a98a8BrainThe brain is an organ that serves as the cente...How are neurons connected?{'text': ['synapses'], 'answer_start': [602]}{'split': 'train', 'model_in_the_loop': 'Combi...
37a0f8e785a10f6e21e24207d24ba2823162383062BrainThe SCN projects to a set of areas in the hypo...The body's central biological clock is contain...{'text': ['SCN'], 'answer_start': [4]}{'split': 'train', 'model_in_the_loop': 'Combi...
536d753d4a8878b5f5bc496d9a369b8c0b212079a0BrainThe brain contains several motor areas that pr...What is at the highest level?{'text': ['the primary motor cortex'], 'answer...{'split': 'train', 'model_in_the_loop': 'Combi...
\n", - "
" - ], - "text/plain": [ - " id title \\\n", - "0 7ba1e8f4261d3170fcf42e84a81dd749116fae95 Brain \n", - "12 936a8460bfffe437b54cf3ec1e825a3b7b5627a1 Brain \n", - "24 e40737d487964dbcd26a223f2799cf56390a98a8 Brain \n", - "37 a0f8e785a10f6e21e24207d24ba2823162383062 Brain \n", - "53 6d753d4a8878b5f5bc496d9a369b8c0b212079a0 Brain \n", - "\n", - " context \\\n", - "0 Another approach to brain function is to exami... \n", - "12 Motor systems are areas of the brain that are ... \n", - "24 The brain is an organ that serves as the cente... \n", - "37 The SCN projects to a set of areas in the hypo... \n", - "53 The brain contains several motor areas that pr... \n", - "\n", - " question \\\n", - "0 What sare the benifts of the blood brain barrir? \n", - "12 What do you think with? \n", - "24 How are neurons connected? \n", - "37 The body's central biological clock is contain... \n", - "53 What is at the highest level? \n", - "\n", - " answers \\\n", - "0 {'text': ['isolated from the bloodstream'], 'a... \n", - "12 {'text': ['brain'], 'answer_start': [467]} \n", - "24 {'text': ['synapses'], 'answer_start': [602]} \n", - "37 {'text': ['SCN'], 'answer_start': [4]} \n", - "53 {'text': ['the primary motor cortex'], 'answer... \n", - "\n", - " metadata \n", - "0 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "12 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "24 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "37 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "53 {'split': 'train', 'model_in_the_loop': 'Combi... " - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data = load_dataset(\"adversarial_qa\", 'adversarialQA', split=\"train\").to_pandas()\n", - "data = data.drop_duplicates(subset=[\"context\"])\n", - "print(f\"Number of unique contexts: {len(data)}\")\n", - "data.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'id': '7ba1e8f4261d3170fcf42e84a81dd749116fae95',\n", - " 'text': 'Another approach to brain function is to examine the consequences of damage to specific brain areas. Even though it is protected by the skull and meninges, surrounded by cerebrospinal fluid, and isolated from the bloodstream by the blood–brain barrier, the delicate nature of the brain makes it vulnerable to numerous diseases and several types of damage. In humans, the effects of strokes and other types of brain damage have been a key source of information about brain function. Because there is no ability to experimentally control the nature of the damage, however, this information is often difficult to interpret. In animal studies, most commonly involving rats, it is possible to use electrodes or locally injected chemicals to produce precise patterns of damage and then examine the consequences for behavior.',\n", - " 'metadata': {'title': 'Brain'}},\n", - " {'id': '936a8460bfffe437b54cf3ec1e825a3b7b5627a1',\n", - " 'text': 'Motor systems are areas of the brain that are directly or indirectly involved in producing body movements, that is, in activating muscles. Except for the muscles that control the eye, which are driven by nuclei in the midbrain, all the voluntary muscles in the body are directly innervated by motor neurons in the spinal cord and hindbrain. Spinal motor neurons are controlled both by neural circuits intrinsic to the spinal cord, and by inputs that descend from the brain. The intrinsic spinal circuits implement many reflex responses, and contain pattern generators for rhythmic movements such as walking or swimming. The descending connections from the brain allow for more sophisticated control.',\n", - " 'metadata': {'title': 'Brain'}},\n", - " {'id': 'e40737d487964dbcd26a223f2799cf56390a98a8',\n", - " 'text': \"The brain is an organ that serves as the center of the nervous system in all vertebrate and most invertebrate animals. Only a few invertebrates such as sponges, jellyfish, adult sea squirts and starfish do not have a brain; diffuse or localised nerve nets are present instead. The brain is located in the head, usually close to the primary sensory organs for such senses as vision, hearing, balance, taste, and smell. The brain is the most complex organ in a vertebrate's body. In a typical human, the cerebral cortex (the largest part) is estimated to contain 15–33 billion neurons, each connected by synapses to several thousand other neurons. These neurons communicate with one another by means of long protoplasmic fibers called axons, which carry trains of signal pulses called action potentials to distant parts of the brain or body targeting specific recipient cells.\",\n", - " 'metadata': {'title': 'Brain'}}]" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Formatting the documents for the retrieval plugin requests\n", - "documents = [\n", - " {\n", - " 'id': r['id'],\n", - " 'text': r['context'],\n", - " 'metadata': {\n", - " 'title': r['title']\n", - " }\n", - " } for r in data.to_dict(orient='records')\n", - "]\n", - "documents[:3]" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Insert data to the HNSW Index" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 27/27 [00:38<00:00, 1.44s/it]\n" - ] - } - ], - "source": [ - "batchSize = 100\n", - "s = requests.Session()\n", - "\n", - "for i in tqdm(range(0, len(documents), batchSize)):\n", - " i_end = min(len(documents), i+batchSize)\n", - " res = s.post(\n", - " \"http://localhost:8000/upsert\",\n", - " headers=headers,\n", - " json={\n", - " \"documents\": documents[i:i_end]\n", - " }\n", - " )" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Query the HNSW index" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[{'query': 'Who went into orbit following Gagarin?'}, {'query': 'Who was responsible for being the best in the Soveit space prgram?'}]\n" - ] - } - ], - "source": [ - "# Select questions from the AdversarialQA dataset\n", - "queries = data['question'].tolist()\n", - "\n", - "queries = [{'query': queries[i]} for i in range(len(queries))]\n", - "searchQueries = queries[150:152]\n", - "print(searchQueries)" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "results = requests.post(\n", - " \"http://0.0.0.0:8000/query\",\n", - " headers=headers,\n", - " json={\n", - " 'queries': searchQueries\n", - " }\n", - ")\n", - "results" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "----------------------------------------------------------------------\n", - "Who went into orbit following Gagarin?\n", - "\n", - "0.35: On May 1, 1960, a U.S. one-man U-2 spy plane was reportedly shot down at high altitude over Soviet Union airspace. The flight was made to gain photo intelligence before the scheduled opening of an East–West summit conference, which had been scheduled in Paris, 15 days later. Captain Francis Gary Powers had bailed out of his aircraft and was captured after parachuting down onto Russian soil. Four days after Powers disappeared, the Eisenhower Administration had NASA issue a very detailed press release noting that an aircraft had \"gone missing\" north of Turkey. It speculated that the pilot might have fallen unconscious while the autopilot was still engaged, and falsely claimed that \"the pilot reported over the emergency frequency that he was experiencing oxygen difficulties.\n", - "0.46: In 1955 American nuclear arms policy became one aimed primarily at arms control as opposed to disarmament. The failure of negotiations over arms until 1955 was due mainly to the refusal of the Russians to permit any sort of inspections. In talks located in London that year, they expressed a willingness to discuss inspections; the tables were then turned on Eisenhower, when he responded with an unwillingness on the part of the U.S. to permit inspections. In May of that year the Russians agreed to sign a treaty giving independence to Austria, and paved the way for a Geneva summit with the U.S., U.K. and France. At the Geneva Conference Eisenhower presented a proposal called \"Open Skies\" to facilitate disarmament, which included plans for Russia and the U.S. to provide mutual access to each other's skies for open surveillance of military infrastructure. Russian leader Nikita Khrushchev dismissed the proposal out of hand.\n", - "0.5: On 6 August 1940, Estonia was annexed by the Soviet Union as the Estonian SSR. The provisions in the Estonian constitution requiring a popular referendum to decide on joining a supra-national body were ignored. Instead the vote to join the Soviet Union was taken by those elected in the elections held the previous month. Additionally those who had failed to do their \"political duty\" of voting Estonia into the USSR, specifically those who had failed to have their passports stamped for voting, were condemned to death by Soviet tribunals. The repressions followed with the mass deportations carried out by the Soviets in Estonia on 14 June 1941. Many of the country's political and intellectual leaders were killed or deported to remote areas of the USSR by the Soviet authorities in 1940–1941. Repressive actions were also taken against thousands of ordinary people.\n", - "----------------------------------------------------------------------\n", - "\n", - "\n", - "----------------------------------------------------------------------\n", - "Who was responsible for being the best in the Soveit space prgram?\n", - "\n", - "0.46: From 1920, Eisenhower served under a succession of talented generals – Fox Conner, John J. Pershing, Douglas MacArthur and George Marshall. He first became executive officer to General Conner in the Panama Canal Zone, where, joined by Mamie, he served until 1924. Under Conner's tutelage, he studied military history and theory (including Carl von Clausewitz's On War), and later cited Conner's enormous influence on his military thinking, saying in 1962 that \"Fox Conner was the ablest man I ever knew.\" Conner's comment on Eisenhower was, \"[He] is one of the most capable, efficient and loyal officers I have ever met.\" On Conner's recommendation, in 1925–26 he attended the Command and General Staff College at Fort Leavenworth, Kansas, where he graduated first in a class of 245 officers.\n", - "0.47: On May 1, 1960, a U.S. one-man U-2 spy plane was reportedly shot down at high altitude over Soviet Union airspace. The flight was made to gain photo intelligence before the scheduled opening of an East–West summit conference, which had been scheduled in Paris, 15 days later. Captain Francis Gary Powers had bailed out of his aircraft and was captured after parachuting down onto Russian soil. Four days after Powers disappeared, the Eisenhower Administration had NASA issue a very detailed press release noting that an aircraft had \"gone missing\" north of Turkey. It speculated that the pilot might have fallen unconscious while the autopilot was still engaged, and falsely claimed that \"the pilot reported over the emergency frequency that he was experiencing oxygen difficulties.\n", - "0.49: RCA/Jive Label Group CEO Barry Weiss left the company in March 2011 to become the new CEO of Island Def Jam and Universal Republic, which were both part of Universal Music Group. Weiss had been the RCA/Jive Label Group CEO since 2008 and was head of Jive Records since 1991.\n", - "----------------------------------------------------------------------\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for query_response in results.json()['results']:\n", - " query = query_response['query']\n", - " answers = []\n", - " scores = []\n", - " for result in query_response['results']:\n", - " answers.append(result['text'])\n", - " scores.append(round(result['score'], 2))\n", - " # Print the scores and corresponding answers\n", - " print(\"-\"*70+\"\\n\"+query+\"\\n\\n\"+\"\\n\".join([f\"{s}: {a}\" for a, s in zip(answers, scores)])+\"\\n\"+\"-\"*70+\"\\n\\n\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "base", - "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.10" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index 1e1a41bde..fa668cc71 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -1,178 +1,72 @@ -import json import os -import asyncio -import pandas as pd -import numpy as np - +from typing import Dict, List, Optional from loguru import logger -from typing import Any, Dict, List, Optional -from uuid import uuid4 +import pandas as pd from services.date import to_unix_timestamp from datastore.datastore import DataStore from models.models import ( DocumentChunk, - DocumentChunkMetadata, - Source, + DocumentChunkWithScore, DocumentMetadataFilter, QueryResult, QueryWithEmbedding, - DocumentChunkWithScore, ) try: import pykx as kx - print('PyKX version: ' + kx.__version__) + logger.info('PyKX version: ' + kx.__version__) except ImportError: raise ValueError( - "Could not import pykx python package. " - "Please add it to the dependencies." + 'Could not import pykx package.' + 'Please add it to the dependencies.' ) try: - ## New for kdbai_client import kdbai_client as kdbai - print('KDBAI-CLIENT version: ' + kdbai.__version__) - ## + logger.info('KDBAI client version: ' + kdbai.__version__) except ImportError: raise ValueError( - "Could not import kdbai python package. " - "Please add it to the dependencies." + 'Could not import kdbai_client package.' + 'Please add it to the dependencies.' ) +HOST = os.environ.get('KDBAI_HOST', 'localhost') +PORT = int(os.environ.get('KDBAI_PORT', '443')) +PROTOCOL = os.environ.get('KDBAI_PROTOCOL', 'https') +DEFAULT_DIMS = 1536 +DEFAULT_SCHEMA = dict(columns=[ + dict(name='document_id', pytype='str'), + dict(name='text', pytype='bytes'), + dict(name='vecs', vectorIndex=dict(type='flat', metric='L2', dims=DEFAULT_DIMS)), + ]) +SCHEMA = os.environ.get('KDBAI_SCHEMA', DEFAULT_SCHEMA) +TABLE = os.environ.get('KDBAI_TABLE', 'documents') -# DEFAULT_EMBEDDING_MODEL = 'text-embedding-ada-002' - -# The name of the table -KDBAI_COLLECTION = os.environ.get("KDBAI_COLLECTION", "openaiEmbeddings") - -# Directory where conversation memory is saved (?) -KDBAI_PERSISTENCE_DIR = os.environ.get("KDBAI_PERSISTENCE_DIR", "openai") - -# Not needed? -KDBAI_INDEX_PARAMS = os.environ.get("KDBAI_INDEX_PARAMS", None) # {"efConstruction": 8, "efSearch": 8, "M": 32} - -# Not needed? -KDBAI_SEARCH_PARAMS = os.environ.get("KDBAI_SEARCH_PARAMS") - -# Algorithm/index for vector similarity search -DEFAULT_ALGORITHM = os.environ.get("DEFAULT_ALGORITHM") - -# HNSW's Default Parameters -DEFAULT_EFCONSTRUCTION = 8 -DEFAULT_M = 32 - -DEFAULT_DIM = 1536 -UPSERT_BATCH_SIZE = 100 -KDBAI_VECTOR_COL_NAME = "vecs" - - -schema = dict( - columns=[ - dict( - name='vecs', - vectorIndex= - dict( - type='flat', - metric='L2', - dims=DEFAULT_DIM - ) - ), - dict( - name='source', - pytype='bytes' - ), - dict( - name='source_id', - pytype='str' - ), - dict( - name='url', - pytype='bytes' - ), - dict( - name='created_at', - pytype='datetime64[ns]' - ), - dict( - name='author', - pytype='bytes' - ), - dict( - name='document_id', - pytype='str' - ), - dict( - name='text', - pytype='bytes' - ), - dict( - name='chunk_id', - pytype='str' - ) - ] - ) +BATCH_SIZE = 100 class KDBAIDataStore(DataStore): - def __init__( - self, - # name of the collection of embeddings - index_name: str = KDBAI_COLLECTION, - - # where conversation memory is saved - # persist_directory: Optional[str] = KDBAI_PERSISTENCE_DIR, - - # manually input the index params (algorithm, metric, dimensions etc) - # options: Optional[str] = KDBAI_INDEX_PARAMS - ) -> None: - - self._index_name = index_name - - # self._persist_directory = persist_directory - # self._options = options - - # self.search_params = KDBAI_SEARCH_PARAMS or None - + def __init__(self) -> None: try: - - # NEW KDBAI-CLIENT - - # create a new session - print('Creating kdbai Session...') - session = kdbai.Session(host='localhost', port=8082, protocol='http') - print("Tables in current session:") - print(session.list()) + logger.info('Creating KDBAI data store...') + self._session = kdbai.Session(host=HOST, port=PORT, protocol=PROTOCOL) - # create a vector database table using the schema - print('Getting table:') - name = 'testingupsert1' - - try: - self._table = session.create_table(name, schema) - except: - self._table = session.table(name) - - - print('Session tables:') - print(session.list()) - - print('Table schema:') - print(self._table.schema()) - + if TABLE in self._session.list(): + self._table = self._session.table(TABLE) + else: + self._table = self._session.create_table(TABLE, SCHEMA) + except Exception as e: - logger.error(f"Error in creating table: {e}") + logger.error(f'Error while initializing KDBAI data store: {e}.') raise e - - return None - async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: """Upsert chunks into the datastore. @@ -186,103 +80,34 @@ async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: Returns: List[str]: The document_id's that were inserted. """ - - # Initialize a list of ids to return try: - doc_ids: List[str] = [] - - # Initialize a list of vectors to upsert - vecs = [] - # Loop through the dict items + docs = [] for doc_id, chunk_list in chunks.items(): - # Append the id to the ids list - - print(f"doc_id: {doc_id}") - print(f"chunk_list: {chunk_list}") - - doc_ids.append(doc_id) - logger.info(f"Upserting document_id: {doc_id}") - for chunk in chunk_list: - - print(f"chunk: {chunk}") - - # Create a vector tuple of (id, embedding, metadata) - # Convert the metadata object to a dict with unix timestamps for dates - self._metadata = self._kdbai_metadata(chunk.metadata) # chunk.metadata comes from retrieval app - - # Add the text and document id to the metadata DICT - self._metadata["text"] = chunk.text - self._metadata["document_id"] = doc_id - self._metadata["chunk_id"] = chunk.id - - vec = (chunk.embedding, self._metadata) - vecs.append(vec) - - # Slice up our insert data into batches - batches = [ - vecs[i : i + UPSERT_BATCH_SIZE] - for i in range(0, len(vecs), UPSERT_BATCH_SIZE) - ] - - for batch in batches: - - # generates an embedding vector for each item in batch - embeddings = np.array([t[0] for t in batch]) # vec[0] - print("Shape of embeddings vector: ", embeddings.shape) - - df = pd.DataFrame(dict(vecs=list(embeddings))) - - # extracts each metadata item in batch to DataFrame - new_meta_df = pd.DataFrame([t[1] for t in batch]) # vec[1] - - print("DataFrame columns: ", new_meta_df.columns) - - df = pd.concat([df, new_meta_df], axis=1) - + docs.append(dict( + document_id=doc_id, + text=chunk.text, + vecs=chunk.embedding, + )) + df = pd.DataFrame(docs) + + for i in range((len(df)-1)//BATCH_SIZE+1): + batch = df.iloc[i*BATCH_SIZE:(i+1)*BATCH_SIZE] try: - logger.info(f"Upserting batch of size {len(batch[0])}") - - print("Inserting DataFrame:") - print(df) - - self._table.insert(df) - - logger.info(f"Upserted batch successfully") - + self._table.insert(batch, warn=False) except Exception as e: - logger.error(f"Failed to insert batch records, error: {e}") - raise e - - return doc_ids + logger.exception('Failed to insert the batch of documents into the data store.') + + return list(df['document_id']) except Exception as e: - logger.error("Insert to collection failed, error: {}".format(e)) + logger.exception(f'Failed to insert documents into the data store.') return [] - def _kdbai_metadata( - self, metadata: Optional[DocumentChunkMetadata] = None - ) -> Dict[str, Any]: - if metadata is None: - return {} - - kdbai_metadata = {} - - for key, value in metadata.dict().items(): - if value is not None: - if key in ["created_at"]: - kdbai_metadata["created_at"] = to_unix_timestamp(value) - else: - kdbai_metadata[key] = value - - return kdbai_metadata - - - ## QUERY vs SEARCH async def _query( self, - queries: List[QueryWithEmbedding], # a list of embedded query vectors + queries: List[QueryWithEmbedding], ) -> List[QueryResult]: """Query @@ -294,80 +119,26 @@ async def _query( Returns: List[QueryResult]: Results for each search. """ - - # handle each query vector at a time - async def _single_query(query: QueryWithEmbedding) -> QueryResult: - + out = [] + for query in queries: try: - - # if there are no filters, just return the n nearest neighbours and their ids - if query.filter is None: - - # calls search() function from kdbai.Index() - # Input: a batch of query vectors and a number of nearest records to search - # Output: a tuple with 2D Numpy arrays containing the distances and IDs of nearest vectors - #dist, ids = self._index.search(np.array([query.embedding]).astype('float32'), k=query.top_k) - - # NEW KDBAI-CLIENT - search_results = self._table.search(dict(vectors=np.array([query.embedding]).astype('float32'), n=query.top_k)) - dist = search_results["__nn_distance"] - ids = search_results["id"] - - - # HANDLE CASES WHERE WE WANT TO FILTER THE RESULTS (see bottom of file for params here) - - # else: - # whereDict = query.filter.dict() - - # if len(whereDict.keys()) > 1: - # raise ValueError("Only 1 filter is allowed currently.") - - # filterStr = "\""+(''.join([str(list(x)[0]) for x in [whereDict.keys(), whereDict.values()]]))+"\"" - # responses = self._index.filtered_search(np.array([query.embedding]).astype('float32'), filterStr, verbose=1, options=dict(neighbors=query.top_k)).pd() - + resdf = self._table.search(vectors=[query.embedding], n=query.top_k)[0] except Exception as e: - logger.error(f"Error querying index: {e}") + logger.exception(f"Error while processing queries.") raise e - - global table - query_results: List[DocumentChunkWithScore] = [] - # iterate through the query results - for dist, id in zip(dist[0],ids[0]): - - indices = id - score = dist - text = table.loc[table.index == id]["text"].values[0] + docs = [] + for result in resdf.to_dict(orient='record'): + docs.append(DocumentChunkWithScore( + id=result['document_id'], + text=result['text'], + metadata=dict(), + score=result['__nn_distance'], + )) + out.append(QueryResult(query=query.query, results=docs)) - metadata = table.drop(['vecs','text'],axis=1).loc[table.index == id].squeeze().to_dict() - - # If the source is not a valid Source in the Source enum, set it to None - if ( - metadata - and "source" in metadata - and metadata["source"] not in Source.__members__ - ): - metadata["source"] = None - - # Create a document chunk with score object with the result data - result = DocumentChunkWithScore( - id=indices, - score=score, - text=text, - metadata=metadata, - ) - query_results.append(result) - - return QueryResult(query=query.query, results=query_results) - - - # iterate through each query and gather results - results: List[QueryResult] = await asyncio.gather( - *[_single_query(query) for query in queries] - ) + return out - return results - async def delete( self, @@ -375,25 +146,4 @@ async def delete( filter: Optional[DocumentMetadataFilter] = None, delete_all: Optional[bool] = None, ) -> bool: - - # If deleting all, drop collection - try: - if delete_all: - - # NEW KDBAI-CLIENT - self._table.drop() - - # table = table.head(0) - else: - logger.error("Functionality is not implemented yet") - - return True - - except Exception as e: - logger.error("Failed to insert records, error: {}".format(e)) - return [] - - -## query = dict(labels=dict(region, assetClass), -# startTS, endTS, inputTZ, outputTZ, -# filter, groupBy, agg, temporality, sortCols) \ No newline at end of file + raise NotImplementedError From fe40b9f09934a25acd51f61acceaf49a99a528e6 Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Thu, 31 Aug 2023 12:45:40 +0200 Subject: [PATCH 09/28] Add support for KDBAI API key. --- datastore/providers/kdbai_datastore.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index fa668cc71..94a684083 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -39,6 +39,9 @@ HOST = os.environ.get('KDBAI_HOST', 'localhost') PORT = int(os.environ.get('KDBAI_PORT', '443')) PROTOCOL = os.environ.get('KDBAI_PROTOCOL', 'https') +KDBAI_API_KEY = os.environ.get('KDBAI_API_KEY', '') +if KDBAI_API_KEY == '': + KDBAI_API_KEY = None DEFAULT_DIMS = 1536 DEFAULT_SCHEMA = dict(columns=[ @@ -57,7 +60,7 @@ class KDBAIDataStore(DataStore): def __init__(self) -> None: try: logger.info('Creating KDBAI data store...') - self._session = kdbai.Session(host=HOST, port=PORT, protocol=PROTOCOL) + self._session = kdbai.Session(host=HOST, port=PORT, protocol=PROTOCOL, api_key=KDBAI_API_KEY) if TABLE in self._session.list(): self._table = self._session.table(TABLE) From 6b9df03f14f87525620d54487467e863d6b0f2d9 Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Thu, 7 Sep 2023 11:52:35 +0100 Subject: [PATCH 10/28] KXI-28991 working cloud version --- datastore/providers/kdbai_datastore.py | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index 94a684083..e3cb9bd4f 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -36,41 +36,43 @@ ) -HOST = os.environ.get('KDBAI_HOST', 'localhost') -PORT = int(os.environ.get('KDBAI_PORT', '443')) -PROTOCOL = os.environ.get('KDBAI_PROTOCOL', 'https') +KDBAI_ENDPOINT = os.environ.get('KDBAI_ENDPOINT', 'http://localhost:8082') KDBAI_API_KEY = os.environ.get('KDBAI_API_KEY', '') + if KDBAI_API_KEY == '': KDBAI_API_KEY = None DEFAULT_DIMS = 1536 -DEFAULT_SCHEMA = dict(columns=[ - dict(name='document_id', pytype='str'), - dict(name='text', pytype='bytes'), - dict(name='vecs', vectorIndex=dict(type='flat', metric='L2', dims=DEFAULT_DIMS)), +BATCH_SIZE = 100 + +DEFAULT_SCHEMA = dict( + columns=[ + dict(name='document_id', pytype='str'), + dict(name='text', pytype='bytes'), + dict(name='vecs', vectorIndex=dict(type='flat', metric='L2', dims=DEFAULT_DIMS)), ]) + SCHEMA = os.environ.get('KDBAI_SCHEMA', DEFAULT_SCHEMA) TABLE = os.environ.get('KDBAI_TABLE', 'documents') -BATCH_SIZE = 100 - class KDBAIDataStore(DataStore): def __init__(self) -> None: try: - logger.info('Creating KDBAI data store...') - self._session = kdbai.Session(host=HOST, port=PORT, protocol=PROTOCOL, api_key=KDBAI_API_KEY) - + logger.info('Creating KDBAI datastore...') + self._session = kdbai.Session(endpoint=KDBAI_ENDPOINT, api_key=KDBAI_API_KEY) + if TABLE in self._session.list(): self._table = self._session.table(TABLE) else: self._table = self._session.create_table(TABLE, SCHEMA) except Exception as e: - logger.error(f'Error while initializing KDBAI data store: {e}.') + logger.error(f'Error while initializing KDBAI datastore: {e}.') raise e + async def _upsert(self, chunks: Dict[str, List[DocumentChunk]]) -> List[str]: """Upsert chunks into the datastore. From e718e18e01f2a21512a0e5ef23c7bf712546647a Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Thu, 7 Sep 2023 11:58:37 +0100 Subject: [PATCH 11/28] KXI-28991 demo notebook --- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 565 ++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 examples/providers/kdbai/ChatGPT_QA_Demo.ipynb diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb new file mode 100644 index 000000000..ef54fac0d --- /dev/null +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -0,0 +1,565 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# KDB.AI for Q&A with ChatGPT Retrieval Plugin" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Install Python 3.10 if not already installed.\n", + "\n", + "2. Clone the `retrieval-app` repository:\n", + "\n", + "```\n", + "git clone git@github.com:openai/retrieval-app.git\n", + "```\n", + "\n", + "3. Navigate to the app directory:\n", + "\n", + "```\n", + "cd /path/to/retrieval-app\n", + "```\n", + "\n", + "4. Install `poetry`:\n", + "\n", + "```\n", + "pip install poetry\n", + "```\n", + "\n", + "5. Create a new virtual environment:\n", + "\n", + "```\n", + "poetry env use python3.10\n", + "```\n", + "\n", + "6. Install the `retrieval-app` dependencies:\n", + "\n", + " Before installing the dependencies with poetry, we will need to add PyKX and a local KDBAI python package as a dependence in the `pyproject.toml` file. This can be done by by adding the following lines under `[tool.poetry.dependencies]`:\n", + "\n", + "* __pykx = \"^1.6.3\"__\n", + "* __kdbai = { path = \"path/to/kdbai-python-client\" }__\n", + "\n", + " Once these have been added, install dependencies to the poetry environment:\n", + "\n", + "```\n", + "poetry install\n", + "```\n", + "\n", + "7. Set up the KDB.AI Cloud Server\n", + " \n", + " Sign up for an account [here](https://test.qa.cld.kx.com/kdbai/signup/) and verify your email to receive your host url (access endpoint) and KDB.AI API key.\n", + "\n", + "\n", + "8. Set app environment variables:\n", + "\n", + "* `BEARER_TOKEN`: Secret token used by the app to authorize incoming requests. The token can be generated using [jwt.io](https://jwt.io/).\n", + "* `OPENAI_API_KEY`: The OpenAI API key used for generating embeddings with the `text-embedding-ada-002` model. [Get an API key here](https://platform.openai.com/account/api-keys)!\n", + "\n", + "\n", + "9. Set `KDBAI`-specific environment variables:\n", + "\n", + "* `DATASTORE`: set to `kdbai`\n", + "* `KDBAI_ENDPOINT`: set to your Cloud host url ('https://ui.qa.cld.kx.com/instance/abcde12345' - omit '/api/v1/config/table')\n", + "* `KDBAI_API_KEY`: set to your Cloud KDB.AI API key\n", + "\n", + "10. Run the app with:\n", + "\n", + "```\n", + "poetry run start\n", + "```\n", + "The ChatGPT plugin is ready to handle requests when `Application startup complete` is printed to the terminal.\n", + "\n", + "When the application is up and running a FastAPI server exposes the ChatGPT plugin's endpoints for `upserting`, `querying`, and `deleting` documents.\n", + "\n", + "During the start up of the application, a new table named `documents` is created in `KDB.AI` with default parameters `{type='flat', metric='L2', dims=1536}`. This table will contain vector embeddings of the data, with an HNSW index for similarity searching. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import random\n", + "import requests\n", + "from tqdm.auto import tqdm\n", + "from datasets import load_dataset\n", + "\n", + "import openai" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "BEARER_TOKEN = os.environ.get(\"BEARER_TOKEN\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load Dataset from Hugging Face\n", + "\n", + "The Adversarial_QA dataset is chosen for this demo.\n", + "The adversarial human annotation paradigm ensures that these datasets consist of questions that current state-of-the-art models find challenging." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of unique contexts: 2648\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecontextquestionanswersmetadata
07ba1e8f4261d3170fcf42e84a81dd749116fae95BrainAnother approach to brain function is to exami...What sare the benifts of the blood brain barrir?{'text': ['isolated from the bloodstream'], 'a...{'split': 'train', 'model_in_the_loop': 'Combi...
12936a8460bfffe437b54cf3ec1e825a3b7b5627a1BrainMotor systems are areas of the brain that are ...What do you think with?{'text': ['brain'], 'answer_start': [467]}{'split': 'train', 'model_in_the_loop': 'Combi...
24e40737d487964dbcd26a223f2799cf56390a98a8BrainThe brain is an organ that serves as the cente...How are neurons connected?{'text': ['synapses'], 'answer_start': [602]}{'split': 'train', 'model_in_the_loop': 'Combi...
37a0f8e785a10f6e21e24207d24ba2823162383062BrainThe SCN projects to a set of areas in the hypo...The body's central biological clock is contain...{'text': ['SCN'], 'answer_start': [4]}{'split': 'train', 'model_in_the_loop': 'Combi...
536d753d4a8878b5f5bc496d9a369b8c0b212079a0BrainThe brain contains several motor areas that pr...What is at the highest level?{'text': ['the primary motor cortex'], 'answer...{'split': 'train', 'model_in_the_loop': 'Combi...
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 7ba1e8f4261d3170fcf42e84a81dd749116fae95 Brain \n", + "12 936a8460bfffe437b54cf3ec1e825a3b7b5627a1 Brain \n", + "24 e40737d487964dbcd26a223f2799cf56390a98a8 Brain \n", + "37 a0f8e785a10f6e21e24207d24ba2823162383062 Brain \n", + "53 6d753d4a8878b5f5bc496d9a369b8c0b212079a0 Brain \n", + "\n", + " context \\\n", + "0 Another approach to brain function is to exami... \n", + "12 Motor systems are areas of the brain that are ... \n", + "24 The brain is an organ that serves as the cente... \n", + "37 The SCN projects to a set of areas in the hypo... \n", + "53 The brain contains several motor areas that pr... \n", + "\n", + " question \\\n", + "0 What sare the benifts of the blood brain barrir? \n", + "12 What do you think with? \n", + "24 How are neurons connected? \n", + "37 The body's central biological clock is contain... \n", + "53 What is at the highest level? \n", + "\n", + " answers \\\n", + "0 {'text': ['isolated from the bloodstream'], 'a... \n", + "12 {'text': ['brain'], 'answer_start': [467]} \n", + "24 {'text': ['synapses'], 'answer_start': [602]} \n", + "37 {'text': ['SCN'], 'answer_start': [4]} \n", + "53 {'text': ['the primary motor cortex'], 'answer... \n", + "\n", + " metadata \n", + "0 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "12 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "24 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "37 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "53 {'split': 'train', 'model_in_the_loop': 'Combi... " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = load_dataset(\"adversarial_qa\", 'adversarialQA', split=\"train\").to_pandas()\n", + "data = data.drop_duplicates(subset=[\"context\"])\n", + "print(f\"Number of unique contexts: {len(data)}\")\n", + "data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'text': 'Another approach to brain function is to examine the consequences of damage to specific brain areas. Even though it is protected by the skull and meninges, surrounded by cerebrospinal fluid, and isolated from the bloodstream by the blood–brain barrier, the delicate nature of the brain makes it vulnerable to numerous diseases and several types of damage. In humans, the effects of strokes and other types of brain damage have been a key source of information about brain function. Because there is no ability to experimentally control the nature of the damage, however, this information is often difficult to interpret. In animal studies, most commonly involving rats, it is possible to use electrodes or locally injected chemicals to produce precise patterns of damage and then examine the consequences for behavior.'}, {'text': 'Motor systems are areas of the brain that are directly or indirectly involved in producing body movements, that is, in activating muscles. Except for the muscles that control the eye, which are driven by nuclei in the midbrain, all the voluntary muscles in the body are directly innervated by motor neurons in the spinal cord and hindbrain. Spinal motor neurons are controlled both by neural circuits intrinsic to the spinal cord, and by inputs that descend from the brain. The intrinsic spinal circuits implement many reflex responses, and contain pattern generators for rhythmic movements such as walking or swimming. The descending connections from the brain allow for more sophisticated control.'}, {'text': \"The brain is an organ that serves as the center of the nervous system in all vertebrate and most invertebrate animals. Only a few invertebrates such as sponges, jellyfish, adult sea squirts and starfish do not have a brain; diffuse or localised nerve nets are present instead. The brain is located in the head, usually close to the primary sensory organs for such senses as vision, hearing, balance, taste, and smell. The brain is the most complex organ in a vertebrate's body. In a typical human, the cerebral cortex (the largest part) is estimated to contain 15–33 billion neurons, each connected by synapses to several thousand other neurons. These neurons communicate with one another by means of long protoplasmic fibers called axons, which carry trains of signal pulses called action potentials to distant parts of the brain or body targeting specific recipient cells.\"}]\n" + ] + } + ], + "source": [ + "# extract text data from the dataset and reformat\n", + "documents = [\n", + " {\n", + " 'text': r['context'],\n", + " } for r in data.to_dict(orient='records')\n", + "]\n", + "\n", + "print(documents[:3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Insert data to the KDB.AI table" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `/upsert` instruction is used to insert data to the KDB.AI datastore in batches, with each batch being embedded with `text-embedding-ada-002` before it is added to the table." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "252f863cd65f43a184038f45f0116058", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/27 [00:00\n" + ] + } + ], + "source": [ + "# query the vector database\n", + "results = requests.post(\n", + " \"http://localhost:8000/query\",\n", + " \n", + " headers = {\n", + " \"Authorization\": f\"Bearer {BEARER_TOKEN}\"\n", + " },\n", + " \n", + " json = {\n", + " 'queries': searchQueries\n", + " }\n", + ")\n", + "\n", + "print(results)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the cell below, we iterate through each query and its results, and pass this data to ChatGPT, which uses it to respond to the query with natural language." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "QUERY:\n", + "Pirates traveled in?\n", + "\n", + "CONTEXT:\n", + "0.35: Perhaps the most famous raid by Oeselian pirates occurred in 1187, with the attack on the Swedish town of Sigtuna by Finnic raiders from Couronia and Oesel. Among the casualties of this raid was the Swedish archbishop Johannes. The city remained occupied for some time, contributing to its decline as a center of commerce in the 13th century and the rise of Uppsala, Visby, Kalmar and Stockholm. The Livonian Chronicle describes the Oeselians as using two kinds of ships, the piratica and the liburna. The former was a warship, the latter mainly a merchant ship. A piratica could carry approximately 30 men and had a high prow shaped like a dragon or a snakehead and a rectangular sail. Viking-age treasures from Estonia mostly contain silver coins and bars. Saaremaa has the richest finds of Viking treasures after Gotland in Sweden.\n", + "0.36: After that, ships including the San Jeronimo, Los Reyes and Todos los Santos also visited the islands in different years.\n", + "0.37: The majority of those enslaved and taken to these ports were captured in raids and wars. Usually the captives were taken back to the conquerors' territory as forced labour; after time, they were sometimes acculturated and absorbed into the conquerors' society. A number of slave routes were established throughout Nigeria linking the hinterland areas with the major coastal ports. Some of the more prolific slave traders were linked with the Oyo Empire in the southwest, the Aro Confederacy in the southeast and the Sokoto Caliphate in the north.\n", + "\n", + "RESPONSE: \n", + "Pirates traveled in different types of ships depending on their needs and purposes. Two kinds of ships commonly used by pirates were the piratica and the liburna. The piratica was a warship, capable of carrying approximately 30 men. It had a distinctive high prow, shaped like a dragon or a snakehead, and a rectangular sail. On the other hand, the liburna was primarily a merchant ship but could also be utilized by pirates. These ships allowed pirates to navigate the seas\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "What happened during the 40th year of the 20th century?\n", + "\n", + "CONTEXT:\n", + "0.31: Over the course of the 20th century, the world's per-capita gross domestic product grew by a factor of five, much more than all earlier centuries combined (including the 19th with its Industrial Revolution). Many economists make the case that this understates the magnitude of growth, as many of the goods and services consumed at the end of the 20th century, such as improved medicine (causing world life expectancy to increase by more than two decades) and communications technologies, were not available at any price at its beginning. However, the gulf between the world's rich and poor grew wider, and the majority of the global population remained in the poor side of the divide.\n", + "0.33: The first half of the 20th century in Russia and the Soviet Union was marked by a succession of wars, famines and other disasters, each accompanied by large-scale population losses. Stephen J. Lee estimates that, by the end of World War II in 1945, the Russian population was about 90 million fewer than it could have been otherwise.\n", + "0.37: War work again brought local prosperity during World War II, this time centered on Boeing aircraft. The war dispersed the city's numerous Japanese-American businessmen due to the Japanese American internment. After the war, the local economy dipped. It rose again with Boeing's growing dominance in the commercial airliner market. Seattle celebrated its restored prosperity and made a bid for world recognition with the Century 21 Exposition, the 1962 World's Fair. Another major local economic downturn was in the late 1960s and early 1970s, at a time when Boeing was heavily affected by the oil crises, loss of Government contracts, and costs and delays associated with the Boeing 747. Many people left the area to look for work elsewhere, and two local real estate agents put up a billboard reading \"Will the last person leaving Seattle – Turn out the lights.\n", + "\n", + "RESPONSE: \n", + "The 40th year of the 20th century was 1940. During this year, several significant events took place. World War II was underway, with Germany invading Denmark and Norway and launching the Battle of France. The Battle of Britain also took place, as Germany attempted to invade the United Kingdom through an aerial campaign. In the Soviet Union, the Great Purge continued, resulting in widespread political repression and execution of perceived enemies of the state. Additionally, the United States implemented the Selective\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "Who rebelled against the Germans with northern Estonia?\n", + "\n", + "CONTEXT:\n", + "0.29: The unsuccessful rebellion led to a consolidation of power for the Baltic German minority. For the subsequent centuries they remained the ruling elite in both cities and in the countryside.\n", + "0.32: On 6 August 1940, Estonia was annexed by the Soviet Union as the Estonian SSR. The provisions in the Estonian constitution requiring a popular referendum to decide on joining a supra-national body were ignored. Instead the vote to join the Soviet Union was taken by those elected in the elections held the previous month. Additionally those who had failed to do their \"political duty\" of voting Estonia into the USSR, specifically those who had failed to have their passports stamped for voting, were condemned to death by Soviet tribunals. The repressions followed with the mass deportations carried out by the Soviets in Estonia on 14 June 1941. Many of the country's political and intellectual leaders were killed or deported to remote areas of the USSR by the Soviet authorities in 1940–1941. Repressive actions were also taken against thousands of ordinary people.\n", + "0.33: From 1228, after of the Livonian Crusade, through the 1560s, Estonia was part of Terra Mariana, established on 2 February 1207 as a principality of the Holy Roman Empire and proclaimed by Pope Innocent III in 1215 as subject to the Holy See. The southern parts of the country were conquered by Livonian Brothers of the Sword who joined the Teutonic Order in 1237 and became its branch known as the Livonian Order. The Duchy of Estonia was created out of the northern parts of the country and was a direct dominion of the King of Denmark from 1219 until 1346, when it was sold to the Teutonic Order and became part of the Ordenstaat. In 1343, the people of northern Estonia and Saaremaa rebelled against German rule in the St. George's Night Uprising, which was put down by 1345.\n", + "\n", + "RESPONSE: \n", + "The people of northern Estonia, along with those from Saaremaa, rebelled against German rule in the St. George's Night Uprising in 1343.\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "__ was known as the king of Estonian folklore.\n", + "\n", + "CONTEXT:\n", + "0.33: As a result of the abolition of serfdom and the availability of education to the native Estonian-speaking population, an active Estonian nationalist movement developed in the 19th century.[citation needed] It began on a cultural level, resulting in the establishment of Estonian language literature, theatre and professional music and led on to the formation of the Estonian national identity and the Age of Awakening. Among the leaders of the movement were Johann Voldemar Jannsen, Jakob Hurt and Carl Robert Jakobson.\n", + "0.34: This strongly suggests that Estonia was an important transit country during the Viking era.\n", + "0.35: The tradition of Estonian Song Festivals (Laulupidu) started at the height of the Estonian national awakening in 1869. Today, it is one of the largest amateur choral events in the world. In 2004, about 100,000 people participated in the Song Festival. Since 1928, the Tallinn Song Festival Grounds (Lauluväljak) have hosted the event every five years in July. The last festival took place in July 2014. In addition, Youth Song Festivals are also held every four or five years, the last of them in 2011, and the next is scheduled for 2017.\n", + "\n", + "RESPONSE: \n", + "Jakob Hurt\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "Which school system is most like a public school system in the US?\n", + "\n", + "CONTEXT:\n", + "0.37: The Boston Public Schools enrolls 57,000 students attending 145 schools, including the renowned Boston Latin Academy, John D. O'Bryant School of Math & Science, and Boston Latin School. The Boston Latin School, established 1635, is the oldest public high school in the US; Boston also operates the United States' second oldest public high school, and its oldest public elementary school. The system's students are 40% Hispanic or Latino, 35% Black or African American, 13% White, and 9% Asian. There are private, parochial, and charter schools as well, and approximately 3,300 minority students attend participating suburban schools through the Metropolitan Educational Opportunity Council.\n", + "0.39: A comprehensive school is a state school that does not select its intake on the basis of academic achievement or aptitude. This is in contrast to the selective school system, where admission is restricted on the basis of selection criteria. The term is commonly used in relation to England and Wales, where comprehensive schools were introduced on an experimental basis in the 1940s and became more widespread from 1965. About 90% of British secondary school pupils now attend comprehensive schools. They correspond broadly to the public high school in the United States and Canada and to the German Gesamtschule.\n", + "0.4: In its 2013 ParkScore ranking, The Trust for Public Land reported that the park system in New York City was the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis. ParkScore ranks urban park systems by a formula that analyzes median park size, park acres as percent of city area, the percent of city residents within a half-mile of a park, spending of park services per resident, and the number of playgrounds per 10,000 residents.\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "RESPONSE: \n", + "The school system in England and Wales, known as comprehensive schools, is most like a public school system in the US. Comprehensive schools do not select students based on academic achievement or aptitude, similar to public schools in the US. Approximately 90% of secondary school students in England and Wales attend comprehensive schools, which are similar to American public high schools.\n", + "\n", + "----------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "# iterate through each set of queries/results\n", + "for query_response in results.json()['results']:\n", + " query = query_response['query']\n", + " answers = []\n", + " scores = []\n", + " \n", + " # extract answers and scores from each result\n", + " for result in query_response['results']:\n", + " \n", + " # answer = textual information related to the query\n", + " answers.append(result['text'])\n", + " \n", + " # score = distance between the query vector and the answer vector (smaller=better!)\n", + " scores.append(round(result['score'], 2))\n", + " \n", + " # print the query\n", + " print(\"\\nQUERY:\\n\"+query)\n", + " \n", + " # print the query responses, and their scores\n", + " print(\"\\nCONTEXT:\\n\"+\"\\n\".join([f\"{s}: {a}\" for a, s in zip(answers, scores)])+\"\\n\")\n", + " \n", + " # format the query and its answers into GPT messages\n", + " messages = [\n", + " {\"role\": \"system\", \"content\": f\"You are a helpful assistant with the following knowledge: {answers}\"},\n", + " {\"role\": \"user\", \"content\": f\"Using your knowledge, answer this query: {query}\"}\n", + " ]\n", + " \n", + " # send the messages to a GPT model\n", + " response = openai.ChatCompletion.create(\n", + " model=\"gpt-3.5-turbo\",\n", + " messages=messages,\n", + " max_tokens=100,\n", + " n=1,\n", + " stop=None, \n", + " )\n", + "\n", + " # extract the generated response from the API response\n", + " generated_response =response['choices'][0]['message']['content']\n", + " \n", + " # Print the generated response\n", + " print(f\"RESPONSE: \\n{generated_response}\\n\")\n", + " print(\"-\"*70)" + ] + } + ], + "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.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 4613245f632dcf78caccde696a62a08365144e0c Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Thu, 7 Sep 2023 17:26:09 +0100 Subject: [PATCH 12/28] KXI-28991 delete --- datastore/providers/kdbai_datastore.py | 31 +++++- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 102 ++++++++++++------ 2 files changed, 98 insertions(+), 35 deletions(-) diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index e3cb9bd4f..9bb61c376 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -151,4 +151,33 @@ async def delete( filter: Optional[DocumentMetadataFilter] = None, delete_all: Optional[bool] = None, ) -> bool: - raise NotImplementedError + + """ + Removes vectors by ids, filter, or everything from the index. + """ + # Delete all vectors from the index if delete_all is True + if delete_all: + try: + logger.info(f"Deleting all vectors from index") + for id in self._session.list(): + self._session.table(id).drop() + logger.info(f"Dropped {id}") + logger.info(f"Deleted all vectors successfully") + return True + + except Exception as e: + logger.error(f"Error deleting all vectors: {e}") + raise e + + if ids is not None and len(ids) > 0: + try: + logger.info(f"Deleting vectors with ids {ids}") + for id in ids: + self._session.table(id).drop() + logger.info(f"Dropped {id}") + logger.info(f"Deleted vectors with ids successfully") + except Exception as e: + logger.error(f"Error deleting vectors with ids: {e}") + raise e + + return True \ No newline at end of file diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index ef54fac0d..2d5fd4111 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -277,6 +277,16 @@ "print(documents[:3])" ] }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# initialise a session with the vector database\n", + "s = requests.Session()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -293,13 +303,13 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "252f863cd65f43a184038f45f0116058", + "model_id": "45a268dbb3774613b8f79a15d8ac4f6b", "version_major": 2, "version_minor": 0 }, @@ -314,9 +324,6 @@ "source": [ "batchSize = 100\n", "\n", - "# initialise a session with the vector database\n", - "s = requests.Session()\n", - "\n", "# upsert documents from the dataset in batches\n", "for i in tqdm(range(0, len(documents), batchSize)):\n", " i_end = min(len(documents), i+batchSize)\n", @@ -343,14 +350,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[{'query': 'Pirates traveled in?'}, {'query': 'What happened during the 40th year of the 20th century?'}, {'query': 'Who rebelled against the Germans with northern Estonia?'}, {'query': '__ was known as the king of Estonian folklore.'}, {'query': 'Which school system is most like a public school system in the US?'}]\n" + "[{'query': 'Are there fewer counties or members in the House of Representatives?'}, {'query': 'What county in Liberia has the largest number of people living there?'}, {'query': \"Which came first, the elections or Taylor's extradition?\"}, {'query': 'How has Portuguese influenced another mentioned language?'}, {'query': \"An adjective that describes characteristics from countries that are not of one's own is?\"}]\n" ] } ], @@ -375,7 +382,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -412,7 +419,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "metadata": { "scrolled": false }, @@ -423,64 +430,64 @@ "text": [ "\n", "QUERY:\n", - "Pirates traveled in?\n", + "Are there fewer counties or members in the House of Representatives?\n", "\n", "CONTEXT:\n", - "0.35: Perhaps the most famous raid by Oeselian pirates occurred in 1187, with the attack on the Swedish town of Sigtuna by Finnic raiders from Couronia and Oesel. Among the casualties of this raid was the Swedish archbishop Johannes. The city remained occupied for some time, contributing to its decline as a center of commerce in the 13th century and the rise of Uppsala, Visby, Kalmar and Stockholm. The Livonian Chronicle describes the Oeselians as using two kinds of ships, the piratica and the liburna. The former was a warship, the latter mainly a merchant ship. A piratica could carry approximately 30 men and had a high prow shaped like a dragon or a snakehead and a rectangular sail. Viking-age treasures from Estonia mostly contain silver coins and bars. Saaremaa has the richest finds of Viking treasures after Gotland in Sweden.\n", - "0.36: After that, ships including the San Jeronimo, Los Reyes and Todos los Santos also visited the islands in different years.\n", - "0.37: The majority of those enslaved and taken to these ports were captured in raids and wars. Usually the captives were taken back to the conquerors' territory as forced labour; after time, they were sometimes acculturated and absorbed into the conquerors' society. A number of slave routes were established throughout Nigeria linking the hinterland areas with the major coastal ports. Some of the more prolific slave traders were linked with the Oyo Empire in the southwest, the Aro Confederacy in the southeast and the Sokoto Caliphate in the north.\n", + "0.3: The Legislature is composed of the Senate and the House of Representatives. The House, led by a speaker, has 73 members apportioned among the 15 counties on the basis of the national census, with each county receiving a minimum of two members. Each House member represents an electoral district within a county as drawn by the National Elections Commission and is elected by a plurality of the popular vote of their district into a six-year term. The Senate is made up of two senators from each county for a total of 30 senators. Senators serve nine-year terms and are elected at-large by a plurality of the popular vote. The vice president serves as the President of the Senate, with a President pro tempore serving in their absence.\n", + "0.36: The House of Representatives currently has 59 members elected for a five-year term, 56 members by proportional representation and 3 observer members representing the Armenian, Latin and Maronite minorities. 24 seats are allocated to the Turkish community but remain vacant since 1964. The political environment is dominated by the communist AKEL, the liberal conservative Democratic Rally, the centrist Democratic Party, the social-democratic EDEK and the centrist EURO.KO. In 2008, Dimitris Christofias became the country's first Communist head of state. Due to his involvement in the 2012–13 Cypriot financial crisis, Christofias did not run for re-election in 2013. The Presidential election in 2013 resulted in Democratic Rally candidate Nicos Anastasiades winning 57.48% of the vote. As a result, Anastasiades was sworn in on and has been President since 28 February 2013.\n", + "0.36: Reapportionment following the 2010 United States Census gave the state two more seats in the House of Representatives. The legislature's redistricting, announced in 2012, was quickly challenged in court, on the grounds that it had unfairly benefited Republican interests. In 2015, the Florida Supreme Court ruled on appeal that the congressional districts had to be redrawn because of the legislature's violation of the Fair District Amendments to the state constitution passed in 2010; it accepted a new map in early December 2015.\n", "\n", "RESPONSE: \n", - "Pirates traveled in different types of ships depending on their needs and purposes. Two kinds of ships commonly used by pirates were the piratica and the liburna. The piratica was a warship, capable of carrying approximately 30 men. It had a distinctive high prow, shaped like a dragon or a snakehead, and a rectangular sail. On the other hand, the liburna was primarily a merchant ship but could also be utilized by pirates. These ships allowed pirates to navigate the seas\n", + "There are fewer counties (15) than members in the House of Representatives (73).\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "What happened during the 40th year of the 20th century?\n", + "What county in Liberia has the largest number of people living there?\n", "\n", "CONTEXT:\n", - "0.31: Over the course of the 20th century, the world's per-capita gross domestic product grew by a factor of five, much more than all earlier centuries combined (including the 19th with its Industrial Revolution). Many economists make the case that this understates the magnitude of growth, as many of the goods and services consumed at the end of the 20th century, such as improved medicine (causing world life expectancy to increase by more than two decades) and communications technologies, were not available at any price at its beginning. However, the gulf between the world's rich and poor grew wider, and the majority of the global population remained in the poor side of the divide.\n", - "0.33: The first half of the 20th century in Russia and the Soviet Union was marked by a succession of wars, famines and other disasters, each accompanied by large-scale population losses. Stephen J. Lee estimates that, by the end of World War II in 1945, the Russian population was about 90 million fewer than it could have been otherwise.\n", - "0.37: War work again brought local prosperity during World War II, this time centered on Boeing aircraft. The war dispersed the city's numerous Japanese-American businessmen due to the Japanese American internment. After the war, the local economy dipped. It rose again with Boeing's growing dominance in the commercial airliner market. Seattle celebrated its restored prosperity and made a bid for world recognition with the Century 21 Exposition, the 1962 World's Fair. Another major local economic downturn was in the late 1960s and early 1970s, at a time when Boeing was heavily affected by the oil crises, loss of Government contracts, and costs and delays associated with the Boeing 747. Many people left the area to look for work elsewhere, and two local real estate agents put up a billboard reading \"Will the last person leaving Seattle – Turn out the lights.\n", + "0.22: Liberia is divided into fifteen counties, which, in turn, are subdivided into a total of 90 districts and further subdivided into clans. The oldest counties are Grand Bassa and Montserrado, both founded in 1839 prior to Liberian independence. Gbarpolu is the newest county, created in 2001. Nimba is the largest of the counties in size at 11,551 km2 (4,460 sq mi), while Montserrado is the smallest at 1,909 km2 (737 sq mi). Montserrado is also the most populous county with 1,144,806 residents as of the 2008 census.\n", + "0.39: In 2010, the literacy rate of Liberia was estimated at 60.8% (64.8% for males and 56.8% for females). In some areas primary and secondary education is free and compulsory from the ages of 6 to 16, though enforcement of attendance is lax. In other areas children are required to pay a tuition fee to attend school. On average, children attain 10 years of education (11 for boys and 8 for girls). The country's education sector is hampered by inadequate schools and supplies, as well as a lack of qualified teachers.\n", + "0.4: The subsequent 2005 elections were internationally regarded as the most free and fair in Liberian history. Ellen Johnson Sirleaf, a Harvard-trained economist and former Minister of Finance, was elected as the first female president in Africa. Upon her inauguration, Sirleaf requested the extradition of Taylor from Nigeria and transferred him to the SCSL for trial in The Hague. In 2006, the government established a Truth and Reconciliation Commission to address the causes and crimes of the civil war.\n", "\n", "RESPONSE: \n", - "The 40th year of the 20th century was 1940. During this year, several significant events took place. World War II was underway, with Germany invading Denmark and Norway and launching the Battle of France. The Battle of Britain also took place, as Germany attempted to invade the United Kingdom through an aerial campaign. In the Soviet Union, the Great Purge continued, resulting in widespread political repression and execution of perceived enemies of the state. Additionally, the United States implemented the Selective\n", + "The county in Liberia with the largest number of people living there is Montserrado. As of the 2008 census, Montserrado had a population of 1,144,806 residents.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "Who rebelled against the Germans with northern Estonia?\n", + "Which came first, the elections or Taylor's extradition?\n", "\n", "CONTEXT:\n", - "0.29: The unsuccessful rebellion led to a consolidation of power for the Baltic German minority. For the subsequent centuries they remained the ruling elite in both cities and in the countryside.\n", - "0.32: On 6 August 1940, Estonia was annexed by the Soviet Union as the Estonian SSR. The provisions in the Estonian constitution requiring a popular referendum to decide on joining a supra-national body were ignored. Instead the vote to join the Soviet Union was taken by those elected in the elections held the previous month. Additionally those who had failed to do their \"political duty\" of voting Estonia into the USSR, specifically those who had failed to have their passports stamped for voting, were condemned to death by Soviet tribunals. The repressions followed with the mass deportations carried out by the Soviets in Estonia on 14 June 1941. Many of the country's political and intellectual leaders were killed or deported to remote areas of the USSR by the Soviet authorities in 1940–1941. Repressive actions were also taken against thousands of ordinary people.\n", - "0.33: From 1228, after of the Livonian Crusade, through the 1560s, Estonia was part of Terra Mariana, established on 2 February 1207 as a principality of the Holy Roman Empire and proclaimed by Pope Innocent III in 1215 as subject to the Holy See. The southern parts of the country were conquered by Livonian Brothers of the Sword who joined the Teutonic Order in 1237 and became its branch known as the Livonian Order. The Duchy of Estonia was created out of the northern parts of the country and was a direct dominion of the King of Denmark from 1219 until 1346, when it was sold to the Teutonic Order and became part of the Ordenstaat. In 1343, the people of northern Estonia and Saaremaa rebelled against German rule in the St. George's Night Uprising, which was put down by 1345.\n", + "0.4: The subsequent 2005 elections were internationally regarded as the most free and fair in Liberian history. Ellen Johnson Sirleaf, a Harvard-trained economist and former Minister of Finance, was elected as the first female president in Africa. Upon her inauguration, Sirleaf requested the extradition of Taylor from Nigeria and transferred him to the SCSL for trial in The Hague. In 2006, the government established a Truth and Reconciliation Commission to address the causes and crimes of the civil war.\n", + "0.41: Democratic Party candidates were consistently elected to local office, increasing the city's ties to the South and its dominant party. In 1861, Mayor Fernando Wood called on the aldermen to declare independence from Albany and the United States after the South seceded, but his proposal was not acted on. Anger at new military conscription laws during the American Civil War (1861–1865), which spared wealthier men who could afford to pay a $300 (equivalent to $5,766 in 2016) commutation fee to hire a substitute, led to the Draft Riots of 1863, whose most visible participants were ethnic Irish working class. The situation deteriorated into attacks on New York's elite, followed by attacks on black New Yorkers and their property after fierce competition for a decade between Irish immigrants and blacks for work.\n", + "0.42: The Times occasionally makes endorsements for foreign elections. In November 2012, it endorsed a second term for Barack Obama although it also expressed reservations about his foreign policy.\n", "\n", "RESPONSE: \n", - "The people of northern Estonia, along with those from Saaremaa, rebelled against German rule in the St. George's Night Uprising in 1343.\n", + "Based on my knowledge, the elections came first. The subsequent 2005 elections in Liberia were internationally regarded as the most free and fair in Liberian history. Ellen Johnson Sirleaf was elected as the first female president in Africa. After her inauguration, Sirleaf requested the extradition of Charles Taylor from Nigeria and transferred him to the Special Court for Sierra Leone (SCSL) for trial in The Hague. Therefore, the elections preceded Taylor's extradition.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "__ was known as the king of Estonian folklore.\n", + "How has Portuguese influenced another mentioned language?\n", "\n", "CONTEXT:\n", - "0.33: As a result of the abolition of serfdom and the availability of education to the native Estonian-speaking population, an active Estonian nationalist movement developed in the 19th century.[citation needed] It began on a cultural level, resulting in the establishment of Estonian language literature, theatre and professional music and led on to the formation of the Estonian national identity and the Age of Awakening. Among the leaders of the movement were Johann Voldemar Jannsen, Jakob Hurt and Carl Robert Jakobson.\n", - "0.34: This strongly suggests that Estonia was an important transit country during the Viking era.\n", - "0.35: The tradition of Estonian Song Festivals (Laulupidu) started at the height of the Estonian national awakening in 1869. Today, it is one of the largest amateur choral events in the world. In 2004, about 100,000 people participated in the Song Festival. Since 1928, the Tallinn Song Festival Grounds (Lauluväljak) have hosted the event every five years in July. The last festival took place in July 2014. In addition, Youth Song Festivals are also held every four or five years, the last of them in 2011, and the next is scheduled for 2017.\n", + "0.32: Portugal's colonial history has long since been a cornerstone of its national identity, as has its geographic position at the south-western corner of Europe, looking out into the Atlantic Ocean. It was one of the last western colonial European powers to give up its overseas territories (among them Angola and Mozambique in 1975), turning over the administration of Macau to the People's Republic of China at the end of 1999. Consequently, it has both influenced and been influenced by cultures from former colonies or dependencies, resulting in immigration from these former territories for both economic and/or personal reasons. Portugal, long a country of emigration (the vast majority of Brazilians have Portuguese ancestry), has now become a country of net immigration, and not just from the last Indian (Portuguese until 1961), African (Portuguese until 1975), and Far East Asian (Portuguese until 1999) overseas territories.\n", + "0.33: According to Ethnologue, the lexical similarity between Catalan and other Romance languages is: 87% with Italian; 85% with Portuguese; 80% with Spanish; 76% with Ladin; 75% with Sardinian; and 73% with Romanian.\n", + "0.33: 14% of the population speaks the official language Portuguese, the language of government and national communication during centuries of colonial rule. 44% speak Kriol, a Portuguese-based creole language, which is effectively a national language of communication among groups. The remainder speak a variety of native African languages unique to ethnicities.\n", "\n", "RESPONSE: \n", - "Jakob Hurt\n", + "According to the given information, Portuguese has influenced Kriol, a Portuguese-based creole language. Kriol is effectively a national language of communication among groups in Portugal. This influence is likely a result of Portugal's colonial history and the extensive use of Portuguese as the language of government and national communication during centuries of colonial rule.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "Which school system is most like a public school system in the US?\n", + "An adjective that describes characteristics from countries that are not of one's own is?\n", "\n", "CONTEXT:\n", - "0.37: The Boston Public Schools enrolls 57,000 students attending 145 schools, including the renowned Boston Latin Academy, John D. O'Bryant School of Math & Science, and Boston Latin School. The Boston Latin School, established 1635, is the oldest public high school in the US; Boston also operates the United States' second oldest public high school, and its oldest public elementary school. The system's students are 40% Hispanic or Latino, 35% Black or African American, 13% White, and 9% Asian. There are private, parochial, and charter schools as well, and approximately 3,300 minority students attend participating suburban schools through the Metropolitan Educational Opportunity Council.\n", - "0.39: A comprehensive school is a state school that does not select its intake on the basis of academic achievement or aptitude. This is in contrast to the selective school system, where admission is restricted on the basis of selection criteria. The term is commonly used in relation to England and Wales, where comprehensive schools were introduced on an experimental basis in the 1940s and became more widespread from 1965. About 90% of British secondary school pupils now attend comprehensive schools. They correspond broadly to the public high school in the United States and Canada and to the German Gesamtschule.\n", - "0.4: In its 2013 ParkScore ranking, The Trust for Public Land reported that the park system in New York City was the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis. ParkScore ranks urban park systems by a formula that analyzes median park size, park acres as percent of city area, the percent of city residents within a half-mile of a park, spending of park services per resident, and the number of playgrounds per 10,000 residents.\n", + "0.43: In most cases this single term is inadequate to describe the geographical range of their operations. The result is multiple definitions.\n", + "0.43: There is no universally accepted criterion for distinguishing two different languages from two dialects (i.e. varieties) of the same language. A number of rough measures exist, sometimes leading to contradictory results. The distinction is therefore subjective and depends on the user's frame of reference. For example, there is discussion about if the Limón Creole English must be considered as \"a kind\" of English or a different language. This creole is spoken in the Caribbean coast of Costa Rica (Central America) by descendant of Jamaican people. The position that Costa Rican linguists support depends on the University they belong.\n", + "0.44: These patterns of discrimination against non-whites have led some academic and other activists to advocate for use of the Portuguese term negro to encompass all African-descended people, in order to stimulate a \"black\" consciousness and identity. This proposal has been criticized since the term pardo is considered to include a wide range of multiracial people, such as caboclos (mestizos), assimilated Amerindians and tri-racials, not only people of partial African and European descent. Trying to identify this entire group as \"black\" would be a false imposition of a different identity from outside the culture and deny people their other, equally valid, ancestries and cultures. It seems a one-drop rule in reverse.\n", "\n" ] }, @@ -489,7 +496,7 @@ "output_type": "stream", "text": [ "RESPONSE: \n", - "The school system in England and Wales, known as comprehensive schools, is most like a public school system in the US. Comprehensive schools do not select students based on academic achievement or aptitude, similar to public schools in the US. Approximately 90% of secondary school students in England and Wales attend comprehensive schools, which are similar to American public high schools.\n", + "The adjective that describes characteristics from countries that are not of one's own is \"foreign.\" However, it is important to note that the concept of \"foreignness\" can vary depending on the perspective or frame of reference of the individual or culture using the term.\n", "\n", "----------------------------------------------------------------------\n" ] @@ -539,6 +546,33 @@ " print(f\"RESPONSE: \\n{generated_response}\\n\")\n", " print(\"-\"*70)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Delete the KDB.AI table" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "res = requests.delete(\n", + " \"http://localhost:8000/delete\",\n", + "\n", + " headers = {\n", + " \"Authorization\": f\"Bearer {BEARER_TOKEN}\"\n", + " },\n", + " \n", + " json = {\n", + " \"ids\": ['documents']\n", + " }\n", + "\n", + ")" + ] } ], "metadata": { From 35a878aade311b42941079cc7a51112f60459289 Mon Sep 17 00:00:00 2001 From: agiannakoulopoulos Date: Thu, 7 Sep 2023 18:31:10 +0100 Subject: [PATCH 13/28] kdbai as vectorstore --- datastore/factory.py | 3 +- poetry.lock | 3194 ++++++++---------------------------------- pyproject.toml | 2 +- 3 files changed, 597 insertions(+), 2602 deletions(-) diff --git a/datastore/factory.py b/datastore/factory.py index a3d8f775f..b18329479 100644 --- a/datastore/factory.py +++ b/datastore/factory.py @@ -65,10 +65,9 @@ async def get_datastore() -> DataStore: from datastore.providers.kdbai_datastore import KDBAIDataStore return KDBAIDataStore() - ) case _: raise ValueError( f"Unsupported vector database: {datastore}. " - f"Try one of the following: llama, elasticsearch, pinecone, weaviate, milvus, zilliz, redis, or qdrant" + f"Try one of the following: kdbai, llama, elasticsearch, pinecone, weaviate, milvus, zilliz, redis, or qdrant" ) diff --git a/poetry.lock b/poetry.lock index a77d3dc17..eb59d6731 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,21 +1,12 @@ -<<<<<<< HEAD -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. - -[[package]] -name = "aiohttp" -version = "3.8.5" -======= # This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohttp" -version = "3.8.4" ->>>>>>> second-repo/main +version = "3.8.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.6" files = [ -<<<<<<< HEAD {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a94159871304770da4dd371f4291b20cac04e8c94f11bdea1c3478e557fbe0d8"}, {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:13bf85afc99ce6f9ee3567b04501f18f9f8dbbb2ea11ed1a2e079670403a7c84"}, {file = "aiohttp-3.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ce2ac5708501afc4847221a521f7e4b245abf5178cf5ddae9d5b3856ddb2f3a"}, @@ -103,95 +94,6 @@ files = [ {file = "aiohttp-3.8.5-cp39-cp39-win32.whl", hash = "sha256:00ad4b6f185ec67f3e6562e8a1d2b69660be43070bd0ef6fcec5211154c7df67"}, {file = "aiohttp-3.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:c0a9034379a37ae42dea7ac1e048352d96286626251862e448933c0f59cbd79c"}, {file = "aiohttp-3.8.5.tar.gz", hash = "sha256:b9552ec52cc147dbf1944ac7ac98af7602e51ea2dcd076ed194ca3c0d1c7d0bc"}, -======= - {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ce45967538fb747370308d3145aa68a074bdecb4f3a300869590f725ced69c1"}, - {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b744c33b6f14ca26b7544e8d8aadff6b765a80ad6164fb1a430bbadd593dfb1a"}, - {file = "aiohttp-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a45865451439eb320784918617ba54b7a377e3501fb70402ab84d38c2cd891b"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86d42d7cba1cec432d47ab13b6637bee393a10f664c425ea7b305d1301ca1a3"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee3c36df21b5714d49fc4580247947aa64bcbe2939d1b77b4c8dcb8f6c9faecc"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:176a64b24c0935869d5bbc4c96e82f89f643bcdf08ec947701b9dbb3c956b7dd"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c844fd628851c0bc309f3c801b3a3d58ce430b2ce5b359cd918a5a76d0b20cb5"}, - {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5393fb786a9e23e4799fec788e7e735de18052f83682ce2dfcabaf1c00c2c08e"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e4b09863aae0dc965c3ef36500d891a3ff495a2ea9ae9171e4519963c12ceefd"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:adfbc22e87365a6e564c804c58fc44ff7727deea782d175c33602737b7feadb6"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:147ae376f14b55f4f3c2b118b95be50a369b89b38a971e80a17c3fd623f280c9"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:eafb3e874816ebe2a92f5e155f17260034c8c341dad1df25672fb710627c6949"}, - {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6cc15d58053c76eacac5fa9152d7d84b8d67b3fde92709195cb984cfb3475ea"}, - {file = "aiohttp-3.8.4-cp310-cp310-win32.whl", hash = "sha256:59f029a5f6e2d679296db7bee982bb3d20c088e52a2977e3175faf31d6fb75d1"}, - {file = "aiohttp-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:fe7ba4a51f33ab275515f66b0a236bcde4fb5561498fe8f898d4e549b2e4509f"}, - {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d8ef1a630519a26d6760bc695842579cb09e373c5f227a21b67dc3eb16cfea4"}, - {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b3f2e06a512e94722886c0827bee9807c86a9f698fac6b3aee841fab49bbfb4"}, - {file = "aiohttp-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a80464982d41b1fbfe3154e440ba4904b71c1a53e9cd584098cd41efdb188ef"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b631e26df63e52f7cce0cce6507b7a7f1bc9b0c501fcde69742130b32e8782f"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f43255086fe25e36fd5ed8f2ee47477408a73ef00e804cb2b5cba4bf2ac7f5e"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d347a172f866cd1d93126d9b239fcbe682acb39b48ee0873c73c933dd23bd0f"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3fec6a4cb5551721cdd70473eb009d90935b4063acc5f40905d40ecfea23e05"}, - {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80a37fe8f7c1e6ce8f2d9c411676e4bc633a8462844e38f46156d07a7d401654"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d1e6a862b76f34395a985b3cd39a0d949ca80a70b6ebdea37d3ab39ceea6698a"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cd468460eefef601ece4428d3cf4562459157c0f6523db89365202c31b6daebb"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:618c901dd3aad4ace71dfa0f5e82e88b46ef57e3239fc7027773cb6d4ed53531"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:652b1bff4f15f6287550b4670546a2947f2a4575b6c6dff7760eafb22eacbf0b"}, - {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80575ba9377c5171407a06d0196b2310b679dc752d02a1fcaa2bc20b235dbf24"}, - {file = "aiohttp-3.8.4-cp311-cp311-win32.whl", hash = "sha256:bbcf1a76cf6f6dacf2c7f4d2ebd411438c275faa1dc0c68e46eb84eebd05dd7d"}, - {file = "aiohttp-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:6e74dd54f7239fcffe07913ff8b964e28b712f09846e20de78676ce2a3dc0bfc"}, - {file = "aiohttp-3.8.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:880e15bb6dad90549b43f796b391cfffd7af373f4646784795e20d92606b7a51"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb96fa6b56bb536c42d6a4a87dfca570ff8e52de2d63cabebfd6fb67049c34b6"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a6cadebe132e90cefa77e45f2d2f1a4b2ce5c6b1bfc1656c1ddafcfe4ba8131"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f352b62b45dff37b55ddd7b9c0c8672c4dd2eb9c0f9c11d395075a84e2c40f75"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ab43061a0c81198d88f39aaf90dae9a7744620978f7ef3e3708339b8ed2ef01"}, - {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9cb1565a7ad52e096a6988e2ee0397f72fe056dadf75d17fa6b5aebaea05622"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:1b3ea7edd2d24538959c1c1abf97c744d879d4e541d38305f9bd7d9b10c9ec41"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7c7837fe8037e96b6dd5cfcf47263c1620a9d332a87ec06a6ca4564e56bd0f36"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3b90467ebc3d9fa5b0f9b6489dfb2c304a1db7b9946fa92aa76a831b9d587e99"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:cab9401de3ea52b4b4c6971db5fb5c999bd4260898af972bf23de1c6b5dd9d71"}, - {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d1f9282c5f2b5e241034a009779e7b2a1aa045f667ff521e7948ea9b56e0c5ff"}, - {file = "aiohttp-3.8.4-cp36-cp36m-win32.whl", hash = "sha256:5e14f25765a578a0a634d5f0cd1e2c3f53964553a00347998dfdf96b8137f777"}, - {file = "aiohttp-3.8.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4c745b109057e7e5f1848c689ee4fb3a016c8d4d92da52b312f8a509f83aa05e"}, - {file = "aiohttp-3.8.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:aede4df4eeb926c8fa70de46c340a1bc2c6079e1c40ccf7b0eae1313ffd33519"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ddaae3f3d32fc2cb4c53fab020b69a05c8ab1f02e0e59665c6f7a0d3a5be54f"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4eb3b82ca349cf6fadcdc7abcc8b3a50ab74a62e9113ab7a8ebc268aad35bb9"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bcb89336efa095ea21b30f9e686763f2be4478f1b0a616969551982c4ee4c3b"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c08e8ed6fa3d477e501ec9db169bfac8140e830aa372d77e4a43084d8dd91ab"}, - {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6cd05ea06daca6ad6a4ca3ba7fe7dc5b5de063ff4daec6170ec0f9979f6c332"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7a00a9ed8d6e725b55ef98b1b35c88013245f35f68b1b12c5cd4100dddac333"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:de04b491d0e5007ee1b63a309956eaed959a49f5bb4e84b26c8f5d49de140fa9"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:40653609b3bf50611356e6b6554e3a331f6879fa7116f3959b20e3528783e699"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dbf3a08a06b3f433013c143ebd72c15cac33d2914b8ea4bea7ac2c23578815d6"}, - {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854f422ac44af92bfe172d8e73229c270dc09b96535e8a548f99c84f82dde241"}, - {file = "aiohttp-3.8.4-cp37-cp37m-win32.whl", hash = "sha256:aeb29c84bb53a84b1a81c6c09d24cf33bb8432cc5c39979021cc0f98c1292a1a"}, - {file = "aiohttp-3.8.4-cp37-cp37m-win_amd64.whl", hash = "sha256:db3fc6120bce9f446d13b1b834ea5b15341ca9ff3f335e4a951a6ead31105480"}, - {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fabb87dd8850ef0f7fe2b366d44b77d7e6fa2ea87861ab3844da99291e81e60f"}, - {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91f6d540163f90bbaef9387e65f18f73ffd7c79f5225ac3d3f61df7b0d01ad15"}, - {file = "aiohttp-3.8.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d265f09a75a79a788237d7f9054f929ced2e69eb0bb79de3798c468d8a90f945"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d89efa095ca7d442a6d0cbc755f9e08190ba40069b235c9886a8763b03785da"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dac314662f4e2aa5009977b652d9b8db7121b46c38f2073bfeed9f4049732cd"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe11310ae1e4cd560035598c3f29d86cef39a83d244c7466f95c27ae04850f10"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ddb2a2026c3f6a68c3998a6c47ab6795e4127315d2e35a09997da21865757f8"}, - {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e75b89ac3bd27d2d043b234aa7b734c38ba1b0e43f07787130a0ecac1e12228a"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6e601588f2b502c93c30cd5a45bfc665faaf37bbe835b7cfd461753068232074"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a5d794d1ae64e7753e405ba58e08fcfa73e3fad93ef9b7e31112ef3c9a0efb52"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a1f4689c9a1462f3df0a1f7e797791cd6b124ddbee2b570d34e7f38ade0e2c71"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3032dcb1c35bc330134a5b8a5d4f68c1a87252dfc6e1262c65a7e30e62298275"}, - {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8189c56eb0ddbb95bfadb8f60ea1b22fcfa659396ea36f6adcc521213cd7b44d"}, - {file = "aiohttp-3.8.4-cp38-cp38-win32.whl", hash = "sha256:33587f26dcee66efb2fff3c177547bd0449ab7edf1b73a7f5dea1e38609a0c54"}, - {file = "aiohttp-3.8.4-cp38-cp38-win_amd64.whl", hash = "sha256:e595432ac259af2d4630008bf638873d69346372d38255774c0e286951e8b79f"}, - {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5a7bdf9e57126dc345b683c3632e8ba317c31d2a41acd5800c10640387d193ed"}, - {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:22f6eab15b6db242499a16de87939a342f5a950ad0abaf1532038e2ce7d31567"}, - {file = "aiohttp-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7235604476a76ef249bd64cb8274ed24ccf6995c4a8b51a237005ee7a57e8643"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea9eb976ffdd79d0e893869cfe179a8f60f152d42cb64622fca418cd9b18dc2a"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92c0cea74a2a81c4c76b62ea1cac163ecb20fb3ba3a75c909b9fa71b4ad493cf"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493f5bc2f8307286b7799c6d899d388bbaa7dfa6c4caf4f97ef7521b9cb13719"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a63f03189a6fa7c900226e3ef5ba4d3bd047e18f445e69adbd65af433add5a2"}, - {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10c8cefcff98fd9168cdd86c4da8b84baaa90bf2da2269c6161984e6737bf23e"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bca5f24726e2919de94f047739d0a4fc01372801a3672708260546aa2601bf57"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:03baa76b730e4e15a45f81dfe29a8d910314143414e528737f8589ec60cf7391"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8c29c77cc57e40f84acef9bfb904373a4e89a4e8b74e71aa8075c021ec9078c2"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:03543dcf98a6619254b409be2d22b51f21ec66272be4ebda7b04e6412e4b2e14"}, - {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17b79c2963db82086229012cff93ea55196ed31f6493bb1ccd2c62f1724324e4"}, - {file = "aiohttp-3.8.4-cp39-cp39-win32.whl", hash = "sha256:34ce9f93a4a68d1272d26030655dd1b58ff727b3ed2a33d80ec433561b03d67a"}, - {file = "aiohttp-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:41a86a69bb63bb2fc3dc9ad5ea9f10f1c9c8e282b471931be0268ddd09430b04"}, - {file = "aiohttp-3.8.4.tar.gz", hash = "sha256:bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -222,37 +124,24 @@ frozenlist = ">=1.1.0" [[package]] name = "anyio" -<<<<<<< HEAD -version = "3.7.1" -======= -version = "3.7.0" ->>>>>>> second-repo/main +version = "4.0.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ -<<<<<<< HEAD - {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, - {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, -======= - {file = "anyio-3.7.0-py3-none-any.whl", hash = "sha256:eddca883c4175f14df8aedce21054bfca3adb70ffe76a9f607aef9d7fa2ea7f0"}, - {file = "anyio-3.7.0.tar.gz", hash = "sha256:275d9973793619a5374e1c89a4f4ad3f4b0a5510a2b5b939444bee8f4c4d37ce"}, ->>>>>>> second-repo/main + {file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"}, + {file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"}, ] [package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" [package.extras] -<<<<<<< HEAD -doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] -======= -doc = ["Sphinx (>=6.1.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme", "sphinxcontrib-jquery"] ->>>>>>> second-repo/main -test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (<0.22)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.22)"] [[package]] name = "arrow" @@ -270,7 +159,6 @@ python-dateutil = ">=2.7.0" [[package]] name = "async-timeout" -<<<<<<< HEAD version = "4.0.3" description = "Timeout context manager for asyncio programs" optional = false @@ -278,15 +166,6 @@ python-versions = ">=3.7" files = [ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, -======= -version = "4.0.2" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.6" -files = [ - {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, - {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ->>>>>>> second-repo/main ] [[package]] @@ -309,22 +188,13 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte [[package]] name = "authlib" -<<<<<<< HEAD version = "1.2.1" -======= -version = "1.2.0" ->>>>>>> second-repo/main description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." optional = false python-versions = "*" files = [ -<<<<<<< HEAD {file = "Authlib-1.2.1-py2.py3-none-any.whl", hash = "sha256:c88984ea00149a90e3537c964327da930779afa4564e354edfd98410bea01911"}, {file = "Authlib-1.2.1.tar.gz", hash = "sha256:421f7c6b468d907ca2d9afede256f068f87e34d23dd221c07d13d4c234726afb"}, -======= - {file = "Authlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:4ddf4fd6cfa75c9a460b361d4bd9dac71ffda0be879dbe4292a02e92349ad55a"}, - {file = "Authlib-1.2.0.tar.gz", hash = "sha256:4fa3e80883a5915ef9f5bc28630564bc4ed5b5af39812a3ff130ec76bd631e9d"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -343,54 +213,32 @@ files = [ [[package]] name = "azure-core" -<<<<<<< HEAD -version = "1.29.2" -======= -version = "1.26.4" ->>>>>>> second-repo/main +version = "1.29.3" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD - {file = "azure-core-1.29.2.zip", hash = "sha256:beb0fe88d1043d8457318e8fb841d9caa648211092eda213c16b376401f3710d"}, - {file = "azure_core-1.29.2-py3-none-any.whl", hash = "sha256:8e6602f322dc1070caf7e17754beb53b69ffa09df0f4786009a3107e9a00c793"}, -======= - {file = "azure-core-1.26.4.zip", hash = "sha256:075fe06b74c3007950dd93d49440c2f3430fd9b4a5a2756ec8c79454afc989c6"}, - {file = "azure_core-1.26.4-py3-none-any.whl", hash = "sha256:d9664b4bc2675d72fba461a285ac43ae33abb2967014a955bf136d9703a2ab3c"}, ->>>>>>> second-repo/main + {file = "azure-core-1.29.3.tar.gz", hash = "sha256:c92700af982e71c8c73de9f4c20da8b3f03ce2c22d13066e4d416b4629c87903"}, + {file = "azure_core-1.29.3-py3-none-any.whl", hash = "sha256:f8b2910f92b66293d93bd00564924ad20ad48f4a1e150577cf18d1e7d4f9263c"}, ] [package.dependencies] requests = ">=2.18.4" six = ">=1.11.0" -<<<<<<< HEAD typing-extensions = ">=4.6.0" -======= -typing-extensions = ">=4.3.0" ->>>>>>> second-repo/main [package.extras] aio = ["aiohttp (>=3.0)"] [[package]] name = "azure-identity" -<<<<<<< HEAD version = "1.14.0" -======= -version = "1.13.0" ->>>>>>> second-repo/main description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "azure-identity-1.14.0.zip", hash = "sha256:72441799f8c5c89bfe21026965e266672a7c5d050c2c65119ef899dd5362e2b1"}, {file = "azure_identity-1.14.0-py3-none-any.whl", hash = "sha256:edabf0e010eb85760e1dd19424d5e8f97ba2c9caff73a16e7b30ccbdbcce369b"}, -======= - {file = "azure-identity-1.13.0.zip", hash = "sha256:c931c27301ffa86b07b4dcf574e29da73e3deba9ab5d1fe4f445bb6a3117e260"}, - {file = "azure_identity-1.13.0-py3-none-any.whl", hash = "sha256:bd700cebb80cd9862098587c29d8677e819beca33c62568ced6d5a8e5e332b82"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -398,10 +246,6 @@ azure-core = ">=1.11.0,<2.0.0" cryptography = ">=2.5" msal = ">=1.20.0,<2.0.0" msal-extensions = ">=0.3.0,<2.0.0" -<<<<<<< HEAD -======= -six = ">=1.12.0" ->>>>>>> second-repo/main [[package]] name = "azure-search-documents" @@ -471,22 +315,13 @@ urllib3 = ">=1.25.3,<3" [[package]] name = "certifi" -<<<<<<< HEAD version = "2023.7.22" -======= -version = "2023.5.7" ->>>>>>> second-repo/main description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ -<<<<<<< HEAD {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, -======= - {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, - {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ->>>>>>> second-repo/main ] [[package]] @@ -567,16 +402,11 @@ pycparser = "*" [[package]] name = "charset-normalizer" -<<<<<<< HEAD version = "3.2.0" -======= -version = "3.1.0" ->>>>>>> second-repo/main description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ -<<<<<<< HEAD {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, @@ -652,103 +482,17 @@ files = [ {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, -======= - {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, - {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, ->>>>>>> second-repo/main ] [[package]] name = "chromadb" -<<<<<<< HEAD version = "0.3.26" -======= -version = "0.3.25" ->>>>>>> second-repo/main description = "Chroma." optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "chromadb-0.3.26-py3-none-any.whl", hash = "sha256:45a7848ee3ed8b694ca5789e5fd723406b76a13fa46f9a9a769f93317f29894c"}, {file = "chromadb-0.3.26.tar.gz", hash = "sha256:a9b596d507f081993f2e32a7dcacabbbec2f6aebc2b6defe524442b07e265296"}, -======= - {file = "chromadb-0.3.25-py3-none-any.whl", hash = "sha256:81afe1850de5b5621570bb3f9d521f42c545091d53d650f8b94a55cd9b69f768"}, - {file = "chromadb-0.3.25.tar.gz", hash = "sha256:78f35c65de7c21622dfc0fe02b6db6b59ba8f04fb8b8cd7b5e5f8f68f9806e8a"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -761,10 +505,7 @@ onnxruntime = ">=1.14.1" overrides = ">=7.3.1" pandas = ">=1.3" posthog = ">=2.4.0" -<<<<<<< HEAD pulsar-client = ">=3.1.0" -======= ->>>>>>> second-repo/main pydantic = ">=1.9" requests = ">=2.28" tokenizers = ">=0.13.2" @@ -774,22 +515,13 @@ uvicorn = {version = ">=0.18.3", extras = ["standard"]} [[package]] name = "click" -<<<<<<< HEAD version = "8.1.7" -======= -version = "8.1.3" ->>>>>>> second-repo/main description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -======= - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -811,149 +543,76 @@ click = "*" [[package]] name = "clickhouse-connect" -<<<<<<< HEAD -version = "0.6.9" +version = "0.6.11" description = "ClickHouse Database Core Driver for Python, Pandas, and Superset" optional = false python-versions = "~=3.7" files = [ - {file = "clickhouse-connect-0.6.9.tar.gz", hash = "sha256:ba735bcb73c4743788e7c8bfeb865edd887da28a253bd189c449df20d9abff64"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74fb1bc9eea037db1361d75adb6482ce6d8c22e4a47a37735edd8e3862d931f7"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb5e4a489b5960fc4bc48fdda052b3a446a736ee4be74105ae7663307da8a063"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e954bfe759fd437595732a15a40356e9e29035a83f485a23601f863aab2f7c6f"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2f4ada702a933f2ffc38e77bf948f11d745f3467191d6b6fc2190683d02bb8"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d06a56e2be745adb692fbf1eedd9fb6d5dbb46ce325c1d9e57b53ba99eee95"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5dcbd145ad907e9bc7dbbc5e80440888201de8f1622f755032595c8b8302e4ef"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f155d1f214c81c5d8e72cbe325dfec72340c082156108db06c862ddd76771d7e"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0b47ec963b9d9cf1674490385183dc988d6e4d33287bb9d81e23373012232223"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-win32.whl", hash = "sha256:59dc14e47fa287578495835e4c5efdff90e40430b5b27a3c1453bb83d65e17cb"}, - {file = "clickhouse_connect-0.6.9-cp310-cp310-win_amd64.whl", hash = "sha256:bcabfaa3fbef4ea9ba723d16e9f50e5e02a3c871b3afc8106b6a04a53a7b19d7"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93025ec43ffc25ae3e5111c0da65f8227dc6ae68834beeda3b0256c22baedd9f"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac72323af794b4c79a804f4f311cfe4ae28426f92ac1b7f390aabbab6a93a4bd"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d8c1e71b34e870d8cd4805c3be86678e19a63931a718f3bf657b48da82c74df"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c286a6814facf3fa5bf492863e99b300154b33c3ecedf7799070ef9b8cd12474"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9924d53302f3333bcc40b9f5238bea4c29c107a6a82e22dc5ba24ce7c1cdb75"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:adf29b7319e5cdb9b6cb8ec3d4e85056e588ac51265b92ffaf6c69481283e643"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6fc2d4e428af2be8c9db23b37f4493848696417376f0eaba23b0e8f053f6a0d4"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b3793d26cabd88bad6f4a3fe9f93974e480cc785f137158be8b58d700baaeb4f"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-win32.whl", hash = "sha256:1fa2fddd00d019b4593b194a303339268699808c5ebeab2d331b2ee0d29eabc0"}, - {file = "clickhouse_connect-0.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:536df34ecb49ddd7c61ebd6b900a7d06b3a246fbe30441cb68c568ea42e292d3"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d61337ca4c48b78a959627e9c0de58b86a8399510de184bd6d4c27b8b7e93c17"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69449ee694ed9aa4ee5f290c13ce5038efe394ff99b43eeee8e8190f3e4aa909"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b97ee1de55fea90f12e1f04ea6521dd827f2ed25361cfb99374cb0649222a8f0"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:adc42d8970b322bf78053a62e6c555fd8e03b29aecffe21521efaf5bad4e2ba4"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:064a27bd8d92f413ddcf20926a6c868a0482f7e757f9d412c0778b875d20c536"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a4aaf279efc5e8e13c6b4ac7ce41a3700f786dd34a58d3686ddf29660364dc62"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:022e0438728cc323d1817ade5105e4458acf71be822dffee130934140524fcbd"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-win32.whl", hash = "sha256:e7a9c511f680e0f40b8765e7fbb8bde6b101cbf0a5b180f6ccc18ad59c9776ea"}, - {file = "clickhouse_connect-0.6.9-cp37-cp37m-win_amd64.whl", hash = "sha256:c2bd8fc5767fd883d5d1ca2e35e3034e590994ea64f76b11a3814ab20862a0b0"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:159cba55d55ea85cea310a8781144559deade5c8cee6b13bc720253e6a6e4a5c"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f4a34a7e3d16c0e4c34a11b7d8cbd633f22ee48e1a193f1977f64fe470ad9c79"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:026b9363553a6bd22f5c9f4b65cacd3c3fc0b50d5d0159c47bb34f63dc87ccff"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaec4e9dc5110bf6f17a0abbb61e286293400d2c3450e29040fd100dc075dc89"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0224509fd36637ccf1add66f4ec12d464e2e80e4a5521e846f4d7602b6664a0c"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aa5b9b5699ae385d4f7c1f493e1029d7803b47c74ecb2502f01fb79135253d2"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1b0418b347f4e7a27e692f6947b9788759b23ee4f4aabccbb376b5241190f8a7"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:80778a118f5b2c52daf64c051fdbc5df23a8c37e9e385205e4942fdd60925d25"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-win32.whl", hash = "sha256:841838e793cd4283d3a245e278b136ea5681e636dcdc816c27c4ff77e4bb2077"}, - {file = "clickhouse_connect-0.6.9-cp38-cp38-win_amd64.whl", hash = "sha256:63de88cf244adda961742c1e05e051340de09714b38cc33d757138af6033b364"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47216788f28fa8d1c225acdd366f5eab53c00b131ca246c7f004d94b1aff7cef"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8b6669ba538b6fe18cbe01f4451c4e5d5674471cd55aec7af3d6f1a8e064b8f"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43de9421a8f91e82efec5f9bffe366fb341e2fb7c7dce89e303061ba7065baa3"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62b184813807112a8ef2853df93b6c07899bdf04f188e547f92c54fc2e056be3"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5c869d6761f38bfb940fa0992078bd7d8ece1c1c47a330ab3e8390ca8b2ba980"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b83f62002ae8a19102f05868639217fe3dddabf4c099dc0ddf1586901f1501fb"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:442f9119a223c4f97608d3e4f38debc9c62873e0e9dc948cb1b21691be35af55"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cef80d7596887eff39256e29a31c23297a1a65aac735b3e0e323c702dd95d2ee"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-win32.whl", hash = "sha256:f9cdccf6fa12349e4c25d099bed1d80274104cc4e4a8110f6692e553f4491b99"}, - {file = "clickhouse_connect-0.6.9-cp39-cp39-win_amd64.whl", hash = "sha256:067b5b104e0ac1e16255313766cd97cccd06285ab36f7a2bea7960bd643f5c13"}, - {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e08de57aeb1272897208f91873511090d3f904fede4e509f9b2a0ff00db4d49"}, - {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5318b4ac3fbf91ed3ab766bfa55b5ce72ba520181ad6f61fbf37ed63150033f4"}, - {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df27dfab1565dce2dad8d6ff41a9bc35fb52ed56fba857f26faffac05ffe201"}, - {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71319fde3214e2382bc7ec402268b9b8c320a2eb86ea764e79a29f7562de06fd"}, - {file = "clickhouse_connect-0.6.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:7e0910ac23e7c1ba9af00818f52cdfc812210b4ab10c2be54f1f6456e144e0a7"}, - {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8566b0b57537b570bbef6736d461108c2354e40bd1b7166f9f51cc2e0d8124cb"}, - {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c7a0f9c9dcb3bb482043a2b0e3ceb371b17d7ad320317529c2834960649fd20"}, - {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70ae9442b369fa6365018ee92cda1fa26eade3b87640c744b8e3d327872cd8ae"}, - {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c018fcf03428f940dfa52eea7ff443dea9eee20c2e161486d0a6d2509693904"}, - {file = "clickhouse_connect-0.6.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:adb7d4a449af756ad9c5b2074ce7844ef34981827cce7510151a8a01493e68f3"}, - {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:66a1d90bcd837734efbe3060f17b98a071f773cac50183efc9a6d2dc40bdbce6"}, - {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41fbc4a75f7098d38246528af34a17b9b7411fb63914787141c82d178bc189be"}, - {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b6da9732b26cd98b8ed672bc7684ccf7a589f8d7f56faa7439f8d78b5f4c32"}, - {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c1954ba9735bf4af6737adc9da68179b6c49b698e288e839705c5c0a260ce85"}, - {file = "clickhouse_connect-0.6.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fa6b01af8c82b860fb4799651dc10a79645b88c8ee103bb14c6e8cdd8b00d8bd"}, -======= -version = "0.5.25" -description = "ClickHouse core driver, SqlAlchemy, and Superset libraries" -optional = false -python-versions = "~=3.7" -files = [ - {file = "clickhouse-connect-0.5.25.tar.gz", hash = "sha256:98af3fff571d1069d2c6dd2f4c0feb220fe4c55bd12608e841c842582061982f"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c8ec7ca17efe105211e7b1271b49e0f6c3c56846488a14a866712ce497ef5a5"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4153d44461535b31f5bf25b79504ba4afa1ed1f03b50fbfc595e34b2b3d2f2"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb5ea544cbabefa99ac588e6a452be6b9e896506b306ebc7a4b073fb3237e6f"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0623d7086710f5c9d04327da1a791ffbf519c0f54b25e3584b6eb88f5496c06b"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:243edb0e30fb52e1e9f137519d342e09e5b804e2e4d1b5d9eea6f90875bd8abe"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:182d5f28a24e2d91921dff6d6fedb51f3622088f340847e46ded93c23b10d8c5"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f6d4d536daf5c0730350cfe1c51dbf0379d07c8272ae288b82fe9a9c47978879"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8918fcd0d14b1ea7d8159a0cef815ec707ec039689f4d4db956b8f4627a48aea"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-win32.whl", hash = "sha256:62819da829bdce30fac58f2266a134b50983f2a9f5808acdde70b0d59e3ed1e1"}, - {file = "clickhouse_connect-0.5.25-cp310-cp310-win_amd64.whl", hash = "sha256:219501ab1180475cbb5fbe604344fd13650507e0bc2618a876f209903dd6738d"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ffe69f2242398845111987672552e2af76a13c0770ce00f82ce84d52f5dd5391"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c701cfc1ae4c9f32aefc9b331224b232b01178ec5692297a827563012b29e2bc"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d8ecae52e5f4d93b7460fb66c61108b77afc28a39bdd6c31dded22865584ec3"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95340f5054a697b36fc9d32f34516583d9a1d4b9c6784860a7454f7d27802d4e"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:657aa2624c532dcc465ef517880823d9c4f2732e792ff51bb306cee1abc4c6a6"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:964cae0de1badc2430927398f172da70c6f322266f8ae2509e7cf83f305a38f5"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0cf33dcb201500cce86c9550f55e0505fa22567ce5314aca01037cf88d139b21"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ff5e4f2098b5363116ec99c79a8f78a81af95eb80086c3df86713dcebb47a36c"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-win32.whl", hash = "sha256:4792f129593f931609e623c64627b2a6b265fc55083e121e3c4cc800ea65bbb3"}, - {file = "clickhouse_connect-0.5.25-cp311-cp311-win_amd64.whl", hash = "sha256:e69421e03ac40c8a5c9f70aca110945b0a7e33843dc415f2305142db9b819941"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e1c285c3452564e99098cce044ef7f6e2041f70f5557022d0f07886d0c17284a"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f501c4f8d92625b0028f828a317beda621bbd6fd26bddada756f2971b0808618"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d2bc8636e262a83f9ee8faf0de6562f463f6b431c6a543be6628006640c0065"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b853b146b3557484946c93b4af22834c83ad30908850dc418dd6085b9367bf59"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4851bb77eba7bbf494b3ee16f71a63cb890947ceddd3d71c2cf5a6635d482987"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:75884207d0e09a9018be29ebe38c0e26be8d0ba96053cc181ee85c15b4ccd18d"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d435e98126754ba82e23d20154ff427117227915ee84c7fea43a8d4444daed2"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-win32.whl", hash = "sha256:d900614c8a85c635b45c30d5de37d287cd0b20e44ef1f7f4b83b392bc82696c7"}, - {file = "clickhouse_connect-0.5.25-cp37-cp37m-win_amd64.whl", hash = "sha256:1c47b203278df80ebd3eccb9087194f35dd666c2d19bca8148dc70d80b94502b"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6d60ec792e72b26184082ec86d4a32d1503acd6725b02bcb56c2980340129837"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e050e67b9b2ce12ec3e7ce5c27d772e54d06dab578393c0760fd2fd8ea9eae57"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e78c9b398abc683f003ed5d3013f2b35d692b8d1a9f1a40dc41fc9fa29304b58"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:805a0494c8a3f4b37f38b33bdf6daeb43ea4165c3d5916e0467a4811f7a1efc6"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62e2da6c3971bc3cfec3dc0430318f38d061ffbdd4eb122e616a2f1aafc6e5c9"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7dbccfc5a7b238c7e927fb159b95f8ab2970ca0fd4ea39c813be4d10d2799cd"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6b9e4d0367f99471e865af55865fe300ccbf6e1d9fa070e1e0048c0f33d1ac2c"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f5bf565a45fb52c5b7e9a96913cda4012c1de1407bbab165378e32c6c946bf0d"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-win32.whl", hash = "sha256:a08ead36c61ac28ce44a0f202acbd594e818be7640d6c972a33a1ebae72e6770"}, - {file = "clickhouse_connect-0.5.25-cp38-cp38-win_amd64.whl", hash = "sha256:0db04a7433d1616f88eaa33b5c5884f7d367d087774a058712a2a6075ac1b4fb"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ffbf42a97a4344b82b934d27749fd8296bb18b29a295c249b5d9a774ad122"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b51c174621c1de9ae03acd31fbd258e51a1760ae39b4c9ffbaec4a38e19e1545"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a59d3d84fccfb831b19a96503fcaf1f6387b49f561d38bf3549fe917a372cc68"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8335abab878fb166494bb9e68bb7d14a7325f96fb656d3f77d7a23668fb67a2f"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0a53d30cc50350efd82ad492a5b5597dedd6b79b19cfd2fe4331eac756f4aeb"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:234579a907e43522c08f1ab9a199d44f7177d7a3755a43669143b237daa026a1"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:93486291893605a0c8884db98e6306f61720fdbe4b1bed5b57cc0daa69cb18c9"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:538025c3e10a387c0fe41b687c3421b98070a7f07d07ca88d7cc0d8aed7650f1"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-win32.whl", hash = "sha256:38051bf7bd6003c0763561214530eef49dc194b062d6bf7faca708f42a5dbf63"}, - {file = "clickhouse_connect-0.5.25-cp39-cp39-win_amd64.whl", hash = "sha256:3618a75a1f2c286e808b1d003ee3956bbf2a762ed36fee5f2a3e2e2096fb37ba"}, - {file = "clickhouse_connect-0.5.25-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2170ba71ad154e9af1f09efd6acaf257b8c1346aeaaf57ae9cac7aa5778bff2c"}, - {file = "clickhouse_connect-0.5.25-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c846104f4e399e50008324c6ae66c3ef45ac4137a67ccaacdd3afe7f2667b05a"}, - {file = "clickhouse_connect-0.5.25-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:697e7c6ea239666aa2695a03787e4fff0c18cb829eb50086f929cf22cc455c7a"}, - {file = "clickhouse_connect-0.5.25-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b093fc58104b1afe5f968394acaa9b665746564e1ed0c7d8ee5aea7a7a2331b"}, - {file = "clickhouse_connect-0.5.25-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4b80e15bff634c4d6a895316b73843f41208d9e22e7e0039e417c79ead5ec906"}, - {file = "clickhouse_connect-0.5.25-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ce9cd94d0d9e022e71cd121555f07c28ad2dbda431e1caf2174ce89a9d792151"}, - {file = "clickhouse_connect-0.5.25-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fec43568dd0424deb9dcc74a804addd91f7119367a4ae77796c59656ba22be9"}, - {file = "clickhouse_connect-0.5.25-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c5bdc7895b05f0a64956b6b4a29da3882a9b805e1d9e0025a061c46791674f3"}, - {file = "clickhouse_connect-0.5.25-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00b54674d9af736f828c438776b7f11e80aecc95a3b763971df20d1537942408"}, - {file = "clickhouse_connect-0.5.25-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:401aa544255f15d6350934db59e6e0b9f1ddc866ccea41803973579725223aea"}, - {file = "clickhouse_connect-0.5.25-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c0a91e08f8563b8710b03c4a3696ba91fa3b0e475aa964a3169f201243f45d76"}, - {file = "clickhouse_connect-0.5.25-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af191fc8ecaa544e065257c99cd1d7f49d62c191d23adb78fd34182525ea2f8f"}, - {file = "clickhouse_connect-0.5.25-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef6cb5437c18e7588d6c3d7f4df6c8cdd883c30f82f8ec4f199cdcea63d189e4"}, - {file = "clickhouse_connect-0.5.25-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5f84058209fbab8119835d9dd475ca4c3a246263d1965f0e7c624bae020cfad"}, - {file = "clickhouse_connect-0.5.25-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b0a12c57233c85edd1a03d7bd153ef68b5392d500d8a1cf21de8cb5698c57481"}, ->>>>>>> second-repo/main + {file = "clickhouse-connect-0.6.11.tar.gz", hash = "sha256:f36395c8670f6b2e6ed5d2fd979f05b2eac3e395e8c3e4dbf90c41b3f8ff0b2d"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:639ebbef11a7c11c7c9c1f51c1c3c2eaadf550df960d14a2de124d8186f8f2d7"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74cb1753ab53a1109196f82d348c4d080e81419a1e3ce89e7c1677d7fab3cafe"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c55b1b05248d2af6fb21ece4ce102db92ac82d47eebbaee649148644c84e21a6"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c363a71a4bfce23d2936b4c69d03c382bee6a7decf7772517b91ea83751a619c"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:968e9081a6c5088c4c7749047d7e442d49f3ec75a34c662d80727348769d3702"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a97a72dac23563bd1cf3b6e2bdc440fc140e024cd7c2e8b0cd4de5fe2ea4eca9"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:47af3c0cd6dab32135abbdcf0e122a19656133940c9d415922ce570162235308"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f6cbb70362171dba25bc2d5390d7d9706a261c5ac9852335132049c91f97ea2f"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-win32.whl", hash = "sha256:7d9a414a738ec0f30ce75117e8014b0e8ebf2bfe436c475c4664d7f6367b488c"}, + {file = "clickhouse_connect-0.6.11-cp310-cp310-win_amd64.whl", hash = "sha256:bf839ca651fa550c68fc7d2fae023ca260522685c113503b89e3487c46175618"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c48f1f0bb56de86c370f918647fcbfe973f0366579a558e5a230f392a5f61487"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bece8b35f8ffdf3354ce21dae1d246b6e88402b852bac2a00f4ee24ac94a9dbd"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fdf44e4ed8acd11709dce1f52e0aa55463c090930708cf3ebe8ca975a5adb4a"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a009a1681a7f01760d9c6706183b146a0c6f67b58bcb4f2443a3caf498464830"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b40c0e6866d80d0fcecad1c34c3a86104e3676d08a5a3979c82202840dee5662"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:63faf2341ee6e7447a31bfc648fd5cbf8d54ed5c1c5be8270ff70f6c3864e622"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:00c260af72909df01e1c27325562d1b72e43e6136b0164d2735b8820e4e0cf28"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6e017a14ee573687a9f8bc739c91b23f4f8d3a464aa13cf690b78c8b2a236143"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-win32.whl", hash = "sha256:b290d7d644222dcc6ec07efb542be193f35b79b8fc3cca027be684508f011d92"}, + {file = "clickhouse_connect-0.6.11-cp311-cp311-win_amd64.whl", hash = "sha256:08795de53a508b284e153d823b9c4373c02cb991d09403a214ffa39f0f04b866"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:502ef4bae3dac9323726c89df2be63858d6aaa0c71907046ab8062038b6b6f8b"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e74ab6e35efbecabce4ac535aa30d54e914b975e8375212525e76d264790d47f"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38fb854cf15ffa1eac5ce5554237447cf6766fbe0cd265f057821178d98d76c8"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe4f1fdc808c472affba07a7117b5aa51536bc313cc47d1e8185bb47d2fa290d"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ade3b7d53396c78acd6018ad5b69ea2717224065c3fd1863cf4c56dfb19666a"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2f25606b3ccc6bbda34279d21ad51b599bca6b983162e5c9f4304e537e00ca64"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8dc0ed0c48ca8a1eece3ace9aa57f733f4fcb93dbb150d18551f0cda3ff4531f"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-win32.whl", hash = "sha256:8927eeb6d4202b72cc42d0df5efba79168ff40b27d836ee48713cb832cde6f8e"}, + {file = "clickhouse_connect-0.6.11-cp37-cp37m-win_amd64.whl", hash = "sha256:c7235debe31d63e4b5c6e1cb954055e708c24b2617ff6e98807ad0c5eb51a345"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0e3faf7a482e14050f2461114b169aea5d1c642e87d54b211742ff29e4c8fe6f"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b6519454eda26e943565f163933e82ebe075c628351bda44354f5c3f03cf5b20"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9597ad4551af5b0f5bc26866dfa1e82cd398cd1298637a1df3ffe2612993bf"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aa4cc8a096fd3eaed1bd536b993fae0ebadd373e24910f813ba11f3c209a5f3"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9fcb18ed7443ee1c466fc4585e7060ce5208fe371f3be77d334446b548d0bc43"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f7c4e88fce75fa0de1a10b2f6f5cd39fac796827a989612338aa04d2c422b3f7"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f7268eef26162cdbf7374804b3a9bfaedbd6141abac125452f0563fe6942e29a"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0069931dfef4dc4d30cb55686473afb9572b1f1d6f249e3d64b02dc0782d30e2"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-win32.whl", hash = "sha256:7cc72769a100ad20f8ca4597acf53b84afa20ce76a2fc760c21f3abbcb20cb94"}, + {file = "clickhouse_connect-0.6.11-cp38-cp38-win_amd64.whl", hash = "sha256:fcd83d48095f1d83dc6a2245d0276592b11bd58e6e398430d1c1cb62d61610cd"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b465566c9d973b9fed03244ac92440c9a7486af5b224e4d11bf7497ff1953f0"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3130ffd160ee6b809de110c01a32fc07a3026ab0438b9f3ff2216c79511d8304"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43e5f3075d644438c4bb9393672ec739e7c1e7c497d4e02d0a0e3a9a205b4d40"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a00264c6539f42074ab6cad22634fafecba75f696569956f0eaad36624b8d5d"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c79c74e18da1d129c96c479c2b17694bed62f7008a4da6129317a2f11e62f7e4"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:66ca83a2ccceb5b70a93288761e6c6279b9b72489ba64ba1ba378448b0c68563"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:697e86c249a8d613a0aac4b91ee4311bcdf3a2b5e1ce58a796de454549dd5e86"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:35846e0503e2d7794b5e81109b1ec3958facbfb5e28997f55b29fc8c37374376"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-win32.whl", hash = "sha256:afd50273adef2ff33cf0a9d176bd19964dfb6cb970b465a82903a1adf291aaf0"}, + {file = "clickhouse_connect-0.6.11-cp39-cp39-win_amd64.whl", hash = "sha256:6d1faf4877799e4f1baeeea44d9bb52f7cd8421fc9a1c871fc01721dfe879cc4"}, + {file = "clickhouse_connect-0.6.11-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b6f8ada7066fcbd7cea2e644c8a1e2af81dd39547ac60fde570732e896fc4cf0"}, + {file = "clickhouse_connect-0.6.11-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b31f978ee92a0e53bdc920e1c59df20569c8e7b5920043d310bcd87d525db30"}, + {file = "clickhouse_connect-0.6.11-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39e1122f75ec97c80395e5a98ffb7cbb4a036bb2f05aa425b8ec048126cfafb2"}, + {file = "clickhouse_connect-0.6.11-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f4bbcf3bdf5937d0c3ca9a0d2ad7c539d6d89415598059f8ad60d550b1fa171"}, + {file = "clickhouse_connect-0.6.11-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a096186cad5475c9ec05cf06e6efd599f2109db734bd7bf8a643fc008916bdf8"}, + {file = "clickhouse_connect-0.6.11-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:63df2068806884ed0898170e6532bb43c1be029cfc4a34ba63c0b05120fb5680"}, + {file = "clickhouse_connect-0.6.11-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e870bad786ee7223676fb01c23f704eccd7cf7af0a4b2c94cef812585551c3a"}, + {file = "clickhouse_connect-0.6.11-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d94e212b1a29d2d6ce071a82574a96925e0e2069d02193c48acf38e5208394cf"}, + {file = "clickhouse_connect-0.6.11-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f12881721752df397396d9a4240b7a2bc5c32fd316766ec50b95537a852a1b6f"}, + {file = "clickhouse_connect-0.6.11-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c2e10d0f718612f2a7e903de02a8921b47bd2fcb1ad1de880506f389090cf262"}, + {file = "clickhouse_connect-0.6.11-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6da4260307a7524efb0f2c797f3cc2e2a89fd3fadddc43b6ef825cadbbc5efd"}, + {file = "clickhouse_connect-0.6.11-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f39f59b77962e7c3861692a6cc11ff59b9354e85a99d432c7f04371a3cdbecba"}, + {file = "clickhouse_connect-0.6.11-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fc3f23c81203178a2d8047117b0cb6e0e969d7cc4ecff61932b971c9452ffef"}, + {file = "clickhouse_connect-0.6.11-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38084d7d0202e88606f70cf6795830818234a8343c8a29bfeb5a1c34bb4e8315"}, + {file = "clickhouse_connect-0.6.11-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:117e31f41c6b6fa46577bb445d50ae6faa080d780f5484e1d302ae685eb349a3"}, ] [package.dependencies] @@ -968,12 +627,7 @@ arrow = ["pyarrow"] numpy = ["numpy"] orjson = ["orjson"] pandas = ["pandas"] -<<<<<<< HEAD sqlalchemy = ["sqlalchemy (>1.3.21,<2.0)"] -======= -sqlalchemy = ["sqlalchemy (>1.3.21,<1.4)"] -superset = ["apache-superset (>=1.4.1)"] ->>>>>>> second-repo/main [[package]] name = "colorama" @@ -1005,131 +659,63 @@ cron = ["capturer (>=2.4)"] [[package]] name = "coverage" -<<<<<<< HEAD -version = "7.3.0" +version = "7.3.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, - {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, - {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, - {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, - {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, - {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, - {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, - {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, - {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, - {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, - {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, - {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, - {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, - {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, -======= -version = "7.2.7" -description = "Code coverage measurement for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, ->>>>>>> second-repo/main + {file = "coverage-7.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd0f7429ecfd1ff597389907045ff209c8fdb5b013d38cfa7c60728cb484b6e3"}, + {file = "coverage-7.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:966f10df9b2b2115da87f50f6a248e313c72a668248be1b9060ce935c871f276"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0575c37e207bb9b98b6cf72fdaaa18ac909fb3d153083400c2d48e2e6d28bd8e"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:245c5a99254e83875c7fed8b8b2536f040997a9b76ac4c1da5bff398c06e860f"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c96dd7798d83b960afc6c1feb9e5af537fc4908852ef025600374ff1a017392"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:de30c1aa80f30af0f6b2058a91505ea6e36d6535d437520067f525f7df123887"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:50dd1e2dd13dbbd856ffef69196781edff26c800a74f070d3b3e3389cab2600d"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9c0c19f70d30219113b18fe07e372b244fb2a773d4afde29d5a2f7930765136"}, + {file = "coverage-7.3.1-cp310-cp310-win32.whl", hash = "sha256:770f143980cc16eb601ccfd571846e89a5fe4c03b4193f2e485268f224ab602f"}, + {file = "coverage-7.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdd088c00c39a27cfa5329349cc763a48761fdc785879220d54eb785c8a38520"}, + {file = "coverage-7.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74bb470399dc1989b535cb41f5ca7ab2af561e40def22d7e188e0a445e7639e3"}, + {file = "coverage-7.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:025ded371f1ca280c035d91b43252adbb04d2aea4c7105252d3cbc227f03b375"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6191b3a6ad3e09b6cfd75b45c6aeeffe7e3b0ad46b268345d159b8df8d835f9"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7eb0b188f30e41ddd659a529e385470aa6782f3b412f860ce22b2491c89b8593"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c8f0df9dfd8ff745bccff75867d63ef336e57cc22b2908ee725cc552689ec8"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eb3cd48d54b9bd0e73026dedce44773214064be93611deab0b6a43158c3d5a0"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ac3c5b7e75acac31e490b7851595212ed951889918d398b7afa12736c85e13ce"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b4ee7080878077af0afa7238df1b967f00dc10763f6e1b66f5cced4abebb0a3"}, + {file = "coverage-7.3.1-cp311-cp311-win32.whl", hash = "sha256:229c0dd2ccf956bf5aeede7e3131ca48b65beacde2029f0361b54bf93d36f45a"}, + {file = "coverage-7.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c6f55d38818ca9596dc9019eae19a47410d5322408140d9a0076001a3dcb938c"}, + {file = "coverage-7.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5289490dd1c3bb86de4730a92261ae66ea8d44b79ed3cc26464f4c2cde581fbc"}, + {file = "coverage-7.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca833941ec701fda15414be400c3259479bfde7ae6d806b69e63b3dc423b1832"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd694e19c031733e446c8024dedd12a00cda87e1c10bd7b8539a87963685e969"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aab8e9464c00da5cb9c536150b7fbcd8850d376d1151741dd0d16dfe1ba4fd26"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d38444efffd5b056fcc026c1e8d862191881143c3aa80bb11fcf9dca9ae204"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8a07b692129b8a14ad7a37941a3029c291254feb7a4237f245cfae2de78de037"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2829c65c8faaf55b868ed7af3c7477b76b1c6ebeee99a28f59a2cb5907a45760"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f111a7d85658ea52ffad7084088277135ec5f368457275fc57f11cebb15607f"}, + {file = "coverage-7.3.1-cp312-cp312-win32.whl", hash = "sha256:c397c70cd20f6df7d2a52283857af622d5f23300c4ca8e5bd8c7a543825baa5a"}, + {file = "coverage-7.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:5ae4c6da8b3d123500f9525b50bf0168023313963e0e2e814badf9000dd6ef92"}, + {file = "coverage-7.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca70466ca3a17460e8fc9cea7123c8cbef5ada4be3140a1ef8f7b63f2f37108f"}, + {file = "coverage-7.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f2781fd3cabc28278dc982a352f50c81c09a1a500cc2086dc4249853ea96b981"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6407424621f40205bbe6325686417e5e552f6b2dba3535dd1f90afc88a61d465"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04312b036580ec505f2b77cbbdfb15137d5efdfade09156961f5277149f5e344"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9ad38204887349853d7c313f53a7b1c210ce138c73859e925bc4e5d8fc18e7"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:53669b79f3d599da95a0afbef039ac0fadbb236532feb042c534fbb81b1a4e40"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:614f1f98b84eb256e4f35e726bfe5ca82349f8dfa576faabf8a49ca09e630086"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1a317fdf5c122ad642db8a97964733ab7c3cf6009e1a8ae8821089993f175ff"}, + {file = "coverage-7.3.1-cp38-cp38-win32.whl", hash = "sha256:defbbb51121189722420a208957e26e49809feafca6afeef325df66c39c4fdb3"}, + {file = "coverage-7.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:f4f456590eefb6e1b3c9ea6328c1e9fa0f1006e7481179d749b3376fc793478e"}, + {file = "coverage-7.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f12d8b11a54f32688b165fd1a788c408f927b0960984b899be7e4c190ae758f1"}, + {file = "coverage-7.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f09195dda68d94a53123883de75bb97b0e35f5f6f9f3aa5bf6e496da718f0cb6"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6601a60318f9c3945be6ea0f2a80571f4299b6801716f8a6e4846892737ebe4"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d156269718670d00a3b06db2288b48527fc5f36859425ff7cec07c6b367745"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:636a8ac0b044cfeccae76a36f3b18264edcc810a76a49884b96dd744613ec0b7"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5d991e13ad2ed3aced177f524e4d670f304c8233edad3210e02c465351f785a0"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:586649ada7cf139445da386ab6f8ef00e6172f11a939fc3b2b7e7c9082052fa0"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4aba512a15a3e1e4fdbfed2f5392ec221434a614cc68100ca99dcad7af29f3f8"}, + {file = "coverage-7.3.1-cp39-cp39-win32.whl", hash = "sha256:6bc6f3f4692d806831c136c5acad5ccedd0262aa44c087c46b7101c77e139140"}, + {file = "coverage-7.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:553d7094cb27db58ea91332e8b5681bac107e7242c23f7629ab1316ee73c4981"}, + {file = "coverage-7.3.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:220eb51f5fb38dfdb7e5d54284ca4d0cd70ddac047d750111a68ab1798945194"}, + {file = "coverage-7.3.1.tar.gz", hash = "sha256:6cb7fe1581deb67b782c153136541e20901aa312ceedaf1467dcb35255787952"}, ] [package.dependencies] @@ -1140,16 +726,11 @@ toml = ["tomli"] [[package]] name = "cryptography" -<<<<<<< HEAD version = "41.0.3" -======= -version = "41.0.0" ->>>>>>> second-repo/main description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507"}, {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922"}, {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81"}, @@ -1173,27 +754,6 @@ files = [ {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1"}, {file = "cryptography-41.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4"}, {file = "cryptography-41.0.3.tar.gz", hash = "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34"}, -======= - {file = "cryptography-41.0.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c5ef25d060c80d6d9f7f9892e1d41bb1c79b78ce74805b8cb4aa373cb7d5ec8"}, - {file = "cryptography-41.0.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8362565b3835ceacf4dc8f3b56471a2289cf51ac80946f9087e66dc283a810e0"}, - {file = "cryptography-41.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3680248309d340fda9611498a5319b0193a8dbdb73586a1acf8109d06f25b92d"}, - {file = "cryptography-41.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84a165379cb9d411d58ed739e4af3396e544eac190805a54ba2e0322feb55c46"}, - {file = "cryptography-41.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab14d567f7bbe7f1cdff1c53d5324ed4d3fc8bd17c481b395db224fb405c237"}, - {file = "cryptography-41.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9f65e842cb02550fac96536edb1d17f24c0a338fd84eaf582be25926e993dde4"}, - {file = "cryptography-41.0.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b7f2f5c525a642cecad24ee8670443ba27ac1fab81bba4cc24c7b6b41f2d0c75"}, - {file = "cryptography-41.0.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d92f0248d38faa411d17f4107fc0bce0c42cae0b0ba5415505df72d751bf62d"}, - {file = "cryptography-41.0.0-cp37-abi3-win32.whl", hash = "sha256:34d405ea69a8b34566ba3dfb0521379b210ea5d560fafedf9f800a9a94a41928"}, - {file = "cryptography-41.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:344c6de9f8bda3c425b3a41b319522ba3208551b70c2ae00099c205f0d9fd3be"}, - {file = "cryptography-41.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:88ff107f211ea696455ea8d911389f6d2b276aabf3231bf72c8853d22db755c5"}, - {file = "cryptography-41.0.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b846d59a8d5a9ba87e2c3d757ca019fa576793e8758174d3868aecb88d6fc8eb"}, - {file = "cryptography-41.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5d0bf9b252f30a31664b6f64432b4730bb7038339bd18b1fafe129cfc2be9be"}, - {file = "cryptography-41.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5c1f7293c31ebc72163a9a0df246f890d65f66b4a40d9ec80081969ba8c78cc9"}, - {file = "cryptography-41.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bf8fc66012ca857d62f6a347007e166ed59c0bc150cefa49f28376ebe7d992a2"}, - {file = "cryptography-41.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a4fc68d1c5b951cfb72dfd54702afdbbf0fb7acdc9b7dc4301bbf2225a27714d"}, - {file = "cryptography-41.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14754bcdae909d66ff24b7b5f166d69340ccc6cb15731670435efd5719294895"}, - {file = "cryptography-41.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0ddaee209d1cf1f180f1efa338a68c4621154de0afaef92b89486f5f96047c55"}, - {file = "cryptography-41.0.0.tar.gz", hash = "sha256:6b71f64beeea341c9b4f963b48ee3b62d62d57ba93eb120e1196b31dc1025e78"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -1211,46 +771,18 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "dataclasses-json" -<<<<<<< HEAD -version = "0.5.9" -======= -version = "0.5.7" ->>>>>>> second-repo/main -description = "Easily serialize dataclasses to and from JSON" +version = "0.6.0" +description = "Easily serialize dataclasses to and from JSON." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7,<4.0" files = [ -<<<<<<< HEAD - {file = "dataclasses-json-0.5.9.tar.gz", hash = "sha256:e9ac87b73edc0141aafbce02b44e93553c3123ad574958f0fe52a534b6707e8e"}, - {file = "dataclasses_json-0.5.9-py3-none-any.whl", hash = "sha256:1280542631df1c375b7bc92e5b86d39e06c44760d7e3571a537b3b8acabf2f0c"}, -======= - {file = "dataclasses-json-0.5.7.tar.gz", hash = "sha256:c2c11bc8214fbf709ffc369d11446ff6945254a7f09128154a7620613d8fda90"}, - {file = "dataclasses_json-0.5.7-py3-none-any.whl", hash = "sha256:bc285b5f892094c3a53d558858a88553dd6a61a11ab1a8128a0e554385dcc5dd"}, ->>>>>>> second-repo/main + {file = "dataclasses_json-0.6.0-py3-none-any.whl", hash = "sha256:77cbc80041007c27db90abad79eeed9ea00d4627324b1208266379a6ebdc81e4"}, + {file = "dataclasses_json-0.6.0.tar.gz", hash = "sha256:5bcd5c1d946a69ef94d8cbb726d87af1256f7ba0898809c7695d299ab9b45122"}, ] [package.dependencies] -marshmallow = ">=3.3.0,<4.0.0" -marshmallow-enum = ">=1.5.1,<2.0.0" -typing-inspect = ">=0.4.0" - -[package.extras] -<<<<<<< HEAD -dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=7.2.0)", "setuptools", "simplejson", "twine", "types-dataclasses", "wheel"] -======= -dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=6.2.3)", "simplejson", "types-dataclasses"] - -[[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -optional = false -python-versions = ">=3.5" -files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] ->>>>>>> second-repo/main +marshmallow = ">=3.18.0,<4.0.0" +typing-inspect = ">=0.4.0,<1" [[package]] name = "deprecation" @@ -1268,7 +800,6 @@ packaging = "*" [[package]] name = "dnspython" -<<<<<<< HEAD version = "2.4.2" description = "DNS toolkit" optional = false @@ -1281,21 +812,6 @@ files = [ [package.extras] dnssec = ["cryptography (>=2.6,<42.0)"] doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"] -======= -version = "2.3.0" -description = "DNS toolkit" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "dnspython-2.3.0-py3-none-any.whl", hash = "sha256:89141536394f909066cabd112e3e1a37e4e654db00a25308b0f130bc3152eb46"}, - {file = "dnspython-2.3.0.tar.gz", hash = "sha256:224e32b03eb46be70e12ef6d64e0be123a64e621ab4c0822ff6d450d52a540b9"}, -] - -[package.extras] -curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] -dnssec = ["cryptography (>=2.6,<40.0)"] -doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.11.0)"] ->>>>>>> second-repo/main doq = ["aioquic (>=0.9.20)"] idna = ["idna (>=2.1,<4.0)"] trio = ["trio (>=0.14,<0.23)"] @@ -1335,16 +851,11 @@ files = [ [[package]] name = "duckdb" -<<<<<<< HEAD version = "0.8.1" -======= -version = "0.8.0" ->>>>>>> second-repo/main description = "DuckDB embedded database" optional = false python-versions = "*" files = [ -<<<<<<< HEAD {file = "duckdb-0.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:14781d21580ee72aba1f5dcae7734674c9b6c078dd60470a08b2b420d15b996d"}, {file = "duckdb-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f13bf7ab0e56ddd2014ef762ae4ee5ea4df5a69545ce1191b8d7df8118ba3167"}, {file = "duckdb-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4032042d8363e55365bbca3faafc6dc336ed2aad088f10ae1a534ebc5bcc181"}, @@ -1397,55 +908,6 @@ files = [ {file = "duckdb-0.8.1-cp39-cp39-win32.whl", hash = "sha256:e7fe93449cd309bbc67d1bf6f6392a6118e94a9a4479ab8a80518742e855370a"}, {file = "duckdb-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:81d670bc6807672f038332d9bf587037aabdd741b0810de191984325ed307abd"}, {file = "duckdb-0.8.1.tar.gz", hash = "sha256:a54d37f4abc2afc4f92314aaa56ecf215a411f40af4bffe1e86bd25e62aceee9"}, -======= - {file = "duckdb-0.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6455aee00af30770c20f4a8c5e4347918cf59b578f49ee996a13807b12911871"}, - {file = "duckdb-0.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b8cf0622ae7f86d4ce72791f8928af4357a46824aadf1b6879c7936b3db65344"}, - {file = "duckdb-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6132e8183ca3ae08a593e43c97cb189794077dedd48546e27ce43bd6a51a9c33"}, - {file = "duckdb-0.8.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe29e5343fa2a95f2cde4519a4f4533f4fd551a48d2d9a8ab5220d40ebf53610"}, - {file = "duckdb-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:945165987ca87c097dc0e578dcf47a100cad77e1c29f5dd8443d53ce159dc22e"}, - {file = "duckdb-0.8.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:673c60daf7ada1d9a8518286a6893ec45efabb64602954af5f3d98f42912fda6"}, - {file = "duckdb-0.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5075fe1ff97ae62331ca5c61e3597e6e9f7682a6fdd418c23ba5c4873ed5cd1"}, - {file = "duckdb-0.8.0-cp310-cp310-win32.whl", hash = "sha256:001f5102f45d3d67f389fa8520046c8f55a99e2c6d43b8e68b38ea93261c5395"}, - {file = "duckdb-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb00800f2e1e865584b13221e0121fce9341bb3a39a93e569d563eaed281f528"}, - {file = "duckdb-0.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b2707096d6df4321044fcde2c9f04da632d11a8be60957fd09d49a42fae71a29"}, - {file = "duckdb-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b27df1b70ae74d2c88efb5ffca8490954fdc678099509a9c4404ca30acc53426"}, - {file = "duckdb-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75a97c800271b52dd0f37696d074c50576dcb4b2750b6115932a98696a268070"}, - {file = "duckdb-0.8.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:804cac261a5e016506a6d67838a65d19b06a237f7949f1704f0e800eb708286a"}, - {file = "duckdb-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6b9abca7fa6713e1d031c18485343b4de99742c7e1b85c10718aa2f31a4e2c6"}, - {file = "duckdb-0.8.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:51aa6d606d49072abcfeb3be209eb559ac94c1b5e70f58ac3adbb94aca9cd69f"}, - {file = "duckdb-0.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7c8dc769aaf2be0a1c57995ca657e5b92c1c56fc8437edb720ca6cab571adf14"}, - {file = "duckdb-0.8.0-cp311-cp311-win32.whl", hash = "sha256:c4207d18b42387c4a035846d8878eb967070198be8ac26fd77797ce320d1a400"}, - {file = "duckdb-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:0c392257547c20794c3072fcbca99a49ef0a49974005d755e93893e2b4875267"}, - {file = "duckdb-0.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2832379e122020814dbe869af7b9ddf3c9f21474cf345531145b099c63ffe17e"}, - {file = "duckdb-0.8.0-cp36-cp36m-win32.whl", hash = "sha256:914896526f7caba86b170f2c4f17f11fd06540325deeb0000cb4fb24ec732966"}, - {file = "duckdb-0.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:022ebda86d0e3204cdc206e4af45aa9f0ae0668b34c2c68cf88e08355af4a372"}, - {file = "duckdb-0.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:96a31c0f3f4ccbf0f5b18f94319f37691205d82f80aae48c6fe04860d743eb2c"}, - {file = "duckdb-0.8.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a07c73c6e6a8cf4ce1a634625e0d1b17e5b817242a8a530d26ed84508dfbdc26"}, - {file = "duckdb-0.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424acbd6e857531b06448d757d7c2557938dbddbff0632092090efbf413b4699"}, - {file = "duckdb-0.8.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c83cfd2a868f1acb0692b9c3fd5ef1d7da8faa1348c6eabf421fbf5d8c2f3eb8"}, - {file = "duckdb-0.8.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5c6f6b2d8db56936f662c649539df81856b5a8cb769a31f9544edf18af2a11ff"}, - {file = "duckdb-0.8.0-cp37-cp37m-win32.whl", hash = "sha256:0bd6376b40a512172eaf4aa816813b1b9d68994292ca436ce626ccd5f77f8184"}, - {file = "duckdb-0.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:931221885bcf1e7dfce2400f11fd048a7beef566b775f1453bb1db89b828e810"}, - {file = "duckdb-0.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:42e7853d963d68e72403ea208bcf806b0f28c7b44db0aa85ce49bb124d56c133"}, - {file = "duckdb-0.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fcc338399175be3d43366576600aef7d72e82114d415992a7a95aded98a0f3fd"}, - {file = "duckdb-0.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:03dd08a4624d6b581a59f9f9dbfd34902416398d16795ad19f92361cf21fd9b5"}, - {file = "duckdb-0.8.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c7c24ea0c9d8563dbd5ad49ccb54b7a9a3c7b8c2833d35e5d32a08549cacea5"}, - {file = "duckdb-0.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb58f6505cc0f34b4e976154302d26563d2e5d16b206758daaa04b65e55d9dd8"}, - {file = "duckdb-0.8.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ef37ac7880100c4b3f913c8483a29a13f8289313b9a07df019fadfa8e7427544"}, - {file = "duckdb-0.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2a4f5ee913ca8a6a069c78f8944b9934ffdbc71fd935f9576fdcea2a6f476f1"}, - {file = "duckdb-0.8.0-cp38-cp38-win32.whl", hash = "sha256:73831c6d7aefcb5f4072cd677b9efebecbf6c578946d21710791e10a1fc41b9a"}, - {file = "duckdb-0.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:faa36d2854734364d234f37d7ef4f3d763b73cd6b0f799cbc2a0e3b7e2575450"}, - {file = "duckdb-0.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:50a31ec237ed619e50f9ab79eb0ec5111eb9697d4475da6e0ab22c08495ce26b"}, - {file = "duckdb-0.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:351abb4cc2d229d043920c4bc2a4c29ca31a79fef7d7ef8f6011cf4331f297bf"}, - {file = "duckdb-0.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:568550a163aca6a787bef8313e358590254de3f4019025a8d68c3a61253fedc1"}, - {file = "duckdb-0.8.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b82617f0e7f9fc080eda217090d82b42d4fad083bc9f6d58dfda9cecb7e3b29"}, - {file = "duckdb-0.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01c9be34d272532b75e8faedda0ff77fa76d1034cde60b8f5768ae85680d6d3"}, - {file = "duckdb-0.8.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8549d6a6bf5f00c012b6916f605416226507e733a3ffc57451682afd6e674d1b"}, - {file = "duckdb-0.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8d145c6d51e55743c3ed1a74cffa109d9e72f82b07e203b436cfa453c925313a"}, - {file = "duckdb-0.8.0-cp39-cp39-win32.whl", hash = "sha256:f8610dfd21e90d7b04e8598b244bf3ad68599fd6ba0daad3428c03cbfd74dced"}, - {file = "duckdb-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:d0f0f104d30418808bafbe9bccdcd238588a07bd246b3cff13842d60bfd8e8ba"}, - {file = "duckdb-0.8.0.tar.gz", hash = "sha256:c68da35bab5072a64ada2646a5b343da620ddc75a7a6e84aa4a1e0628a7ec18f"}, ->>>>>>> second-repo/main ] [[package]] @@ -1484,45 +946,15 @@ elastic-transport = ">=8,<9" async = ["aiohttp (>=3,<4)"] requests = ["requests (>=2.4.0,<3.0.0)"] -[[package]] -name = "environs" -version = "9.5.0" -description = "simplified environment variable parsing" -optional = false -python-versions = ">=3.6" -files = [ - {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, - {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, -] - -[package.dependencies] -marshmallow = ">=3.0.0" -python-dotenv = "*" - -[package.extras] -dev = ["dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "pytest", "tox"] -django = ["dj-database-url", "dj-email-url", "django-cache-url"] -lint = ["flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] -tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"] - [[package]] name = "exceptiongroup" -<<<<<<< HEAD version = "1.1.3" -======= -version = "1.1.1" ->>>>>>> second-repo/main description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, -======= - {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, - {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, ->>>>>>> second-repo/main ] [package.extras] @@ -1551,32 +983,21 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.10.0)", "coverage[toml] (>= [[package]] name = "filelock" -<<<<<<< HEAD -version = "3.12.2" -======= -version = "3.12.0" ->>>>>>> second-repo/main +version = "3.12.3" description = "A platform independent file lock." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ -<<<<<<< HEAD - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.12.3-py3-none-any.whl", hash = "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb"}, + {file = "filelock-3.12.3.tar.gz", hash = "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d"}, ] -[package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] -======= - {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, - {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, -] +[package.dependencies] +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.11\""} [package.extras] -docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] ->>>>>>> second-repo/main +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] [[package]] name = "flatbuffers" @@ -1591,7 +1012,6 @@ files = [ [[package]] name = "frozenlist" -<<<<<<< HEAD version = "1.4.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false @@ -1658,89 +1078,43 @@ files = [ {file = "frozenlist-1.4.0-cp39-cp39-win32.whl", hash = "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f"}, {file = "frozenlist-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167"}, {file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"}, -======= -version = "1.3.3" -description = "A list-like structure which implements collections.abc.MutableSequence" +] + +[[package]] +name = "fsspec" +version = "2023.9.0" +description = "File-system specification" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"}, - {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0"}, - {file = "frozenlist-1.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530"}, - {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7"}, - {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99"}, - {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483"}, - {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd"}, - {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf"}, - {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816"}, - {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0"}, - {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce"}, - {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f"}, - {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420"}, - {file = "frozenlist-1.3.3-cp310-cp310-win32.whl", hash = "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642"}, - {file = "frozenlist-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1"}, - {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7"}, - {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678"}, - {file = "frozenlist-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6"}, - {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8"}, - {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb"}, - {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91"}, - {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b"}, - {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4"}, - {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48"}, - {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d"}, - {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6"}, - {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4"}, - {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81"}, - {file = "frozenlist-1.3.3-cp311-cp311-win32.whl", hash = "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8"}, - {file = "frozenlist-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32"}, - {file = "frozenlist-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332"}, - {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27"}, - {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d"}, - {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e"}, - {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d"}, - {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c"}, - {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56"}, - {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420"}, - {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e"}, - {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb"}, - {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401"}, - {file = "frozenlist-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a"}, - {file = "frozenlist-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411"}, - {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a"}, - {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5"}, - {file = "frozenlist-1.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e"}, - {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c"}, - {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba"}, - {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703"}, - {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2"}, - {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448"}, - {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4"}, - {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649"}, - {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842"}, - {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13"}, - {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3"}, - {file = "frozenlist-1.3.3-cp38-cp38-win32.whl", hash = "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b"}, - {file = "frozenlist-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef"}, - {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf"}, - {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1"}, - {file = "frozenlist-1.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0"}, - {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d"}, - {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936"}, - {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5"}, - {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b"}, - {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669"}, - {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb"}, - {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784"}, - {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d"}, - {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab"}, - {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1"}, - {file = "frozenlist-1.3.3-cp39-cp39-win32.whl", hash = "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38"}, - {file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"}, - {file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"}, ->>>>>>> second-repo/main + {file = "fsspec-2023.9.0-py3-none-any.whl", hash = "sha256:d55b9ab2a4c1f2b759888ae9f93e40c2aa72c0808132e87e282b549f9e6c4254"}, + {file = "fsspec-2023.9.0.tar.gz", hash = "sha256:4dbf0fefee035b7c6d3bbbe6bc99b2f201f40d4dca95b67c2b719be77bcd917f"}, ] +[package.extras] +abfs = ["adlfs"] +adl = ["adlfs"] +arrow = ["pyarrow (>=1)"] +dask = ["dask", "distributed"] +devel = ["pytest", "pytest-cov"] +dropbox = ["dropbox", "dropboxdrivefs", "requests"] +full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] +fuse = ["fusepy"] +gcs = ["gcsfs"] +git = ["pygit2"] +github = ["requests"] +gs = ["gcsfs"] +gui = ["panel"] +hdfs = ["pyarrow (>=1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"] +libarchive = ["libarchive-c"] +oci = ["ocifs"] +s3 = ["s3fs"] +sftp = ["paramiko"] +smb = ["smbprotocol"] +ssh = ["paramiko"] +tqdm = ["tqdm"] + [[package]] name = "gitdb" version = "4.0.10" @@ -1757,22 +1131,13 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -<<<<<<< HEAD -version = "3.1.32" -======= -version = "3.1.31" ->>>>>>> second-repo/main +version = "3.1.35" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD - {file = "GitPython-3.1.32-py3-none-any.whl", hash = "sha256:e3d59b1c2c6ebb9dfa7a184daf3b6dd4914237e7488a1730a6d8f6f5d0b4187f"}, - {file = "GitPython-3.1.32.tar.gz", hash = "sha256:8d9b8cb1e80b9735e8717c9362079d3ce4c6e5ddeebedd0361b228c3a67a62f6"}, -======= - {file = "GitPython-3.1.31-py3-none-any.whl", hash = "sha256:f04893614f6aa713a60cbbe1e6a97403ef633103cdd0ef5eb6efe0deb98dbe8d"}, - {file = "GitPython-3.1.31.tar.gz", hash = "sha256:8ce3bcf69adfdf7c7d503e78fd3b1c492af782d58893b650adb2ac8912ddd573"}, ->>>>>>> second-repo/main + {file = "GitPython-3.1.35-py3-none-any.whl", hash = "sha256:c19b4292d7a1d3c0f653858db273ff8a6614100d1eb1528b014ec97286193c09"}, + {file = "GitPython-3.1.35.tar.gz", hash = "sha256:9cbefbd1789a5fe9bcf621bb34d3f441f3a90c8461d377f84eda73e721d9b06b"}, ] [package.dependencies] @@ -1780,31 +1145,18 @@ gitdb = ">=4.0.1,<5" [[package]] name = "gotrue" -<<<<<<< HEAD -version = "1.0.2" -======= -version = "1.0.1" ->>>>>>> second-repo/main +version = "1.0.4" description = "Python Client Library for GoTrue" optional = false python-versions = ">=3.8,<4.0" files = [ -<<<<<<< HEAD - {file = "gotrue-1.0.2-py3-none-any.whl", hash = "sha256:5377e7fd316b77df7be9e0c3c017d338bed2ba2e95a99fb44374b523d167ec65"}, - {file = "gotrue-1.0.2.tar.gz", hash = "sha256:9ad9b2536ca68676cf37dc663b64f259956826075e80a9cb3f5a3ba150355811"}, + {file = "gotrue-1.0.4-py3-none-any.whl", hash = "sha256:f016f5e317a21e55dfcee00fb360f2c7a33c5b87a38601e7b9e65cb898bcf7bb"}, + {file = "gotrue-1.0.4.tar.gz", hash = "sha256:2686c93b798fb2d3b120f067d21e66bb803b013ee6ab6fb7783093102f74603a"}, ] [package.dependencies] httpx = ">=0.23,<0.25" -======= - {file = "gotrue-1.0.1-py3-none-any.whl", hash = "sha256:005e8bc8d7f2da87606504c9c269f2943245843e2ddefb99e583f45a8612e715"}, - {file = "gotrue-1.0.1.tar.gz", hash = "sha256:9d7e01703beb3c017bcf0461f518f93bc5a400720df3ba8c082264d405cee4d0"}, -] - -[package.dependencies] -httpx = ">=0.23.0,<0.24.0" ->>>>>>> second-repo/main -pydantic = ">=1.10.0,<2.0.0" +pydantic = ">=1.10,<3" [[package]] name = "greenlet" @@ -1881,229 +1233,117 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -<<<<<<< HEAD -version = "1.56.0" -======= -version = "1.53.0" ->>>>>>> second-repo/main +version = "1.57.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD - {file = "grpcio-1.56.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:fb34ace11419f1ae321c36ccaa18d81cd3f20728cd191250be42949d6845bb2d"}, - {file = "grpcio-1.56.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:008767c0aed4899e657b50f2e0beacbabccab51359eba547f860e7c55f2be6ba"}, - {file = "grpcio-1.56.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:17f47aeb9be0da5337f9ff33ebb8795899021e6c0741ee68bd69774a7804ca86"}, - {file = "grpcio-1.56.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43c50d810cc26349b093bf2cfe86756ab3e9aba3e7e681d360930c1268e1399a"}, - {file = "grpcio-1.56.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:187b8f71bad7d41eea15e0c9812aaa2b87adfb343895fffb704fb040ca731863"}, - {file = "grpcio-1.56.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:881575f240eb5db72ddca4dc5602898c29bc082e0d94599bf20588fb7d1ee6a0"}, - {file = "grpcio-1.56.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c243b158dd7585021d16c50498c4b2ec0a64a6119967440c5ff2d8c89e72330e"}, - {file = "grpcio-1.56.0-cp310-cp310-win32.whl", hash = "sha256:8b3b2c7b5feef90bc9a5fa1c7f97637e55ec3e76460c6d16c3013952ee479cd9"}, - {file = "grpcio-1.56.0-cp310-cp310-win_amd64.whl", hash = "sha256:03a80451530fd3b8b155e0c4480434f6be669daf7ecba56f73ef98f94222ee01"}, - {file = "grpcio-1.56.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:64bd3abcf9fb4a9fa4ede8d0d34686314a7075f62a1502217b227991d9ca4245"}, - {file = "grpcio-1.56.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:fdc3a895791af4addbb826808d4c9c35917c59bb5c430d729f44224e51c92d61"}, - {file = "grpcio-1.56.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:4f84a6fd4482e5fe73b297d4874b62a535bc75dc6aec8e9fe0dc88106cd40397"}, - {file = "grpcio-1.56.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14e70b4dda3183abea94c72d41d5930c333b21f8561c1904a372d80370592ef3"}, - {file = "grpcio-1.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b5ce42a5ebe3e04796246ba50357f1813c44a6efe17a37f8dc7a5c470377312"}, - {file = "grpcio-1.56.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8219f17baf069fe8e42bd8ca0b312b875595e43a70cabf397be4fda488e2f27d"}, - {file = "grpcio-1.56.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:defdd14b518e6e468466f799aaa69db0355bca8d3a5ea75fb912d28ba6f8af31"}, - {file = "grpcio-1.56.0-cp311-cp311-win32.whl", hash = "sha256:50f4daa698835accbbcc60e61e0bc29636c0156ddcafb3891c987e533a0031ba"}, - {file = "grpcio-1.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:59c4e606993a47146fbeaf304b9e78c447f5b9ee5641cae013028c4cca784617"}, - {file = "grpcio-1.56.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:b1f4b6f25a87d80b28dd6d02e87d63fe1577fe6d04a60a17454e3f8077a38279"}, - {file = "grpcio-1.56.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:c2148170e01d464d41011a878088444c13413264418b557f0bdcd1bf1b674a0e"}, - {file = "grpcio-1.56.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:0409de787ebbf08c9d2bca2bcc7762c1efe72eada164af78b50567a8dfc7253c"}, - {file = "grpcio-1.56.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66f0369d27f4c105cd21059d635860bb2ea81bd593061c45fb64875103f40e4a"}, - {file = "grpcio-1.56.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38fdf5bd0a1c754ce6bf9311a3c2c7ebe56e88b8763593316b69e0e9a56af1de"}, - {file = "grpcio-1.56.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:79d4c5911d12a7aa671e5eb40cbb50a830396525014d2d6f254ea2ba180ce637"}, - {file = "grpcio-1.56.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5d2fc471668a7222e213f86ef76933b18cdda6a51ea1322034478df8c6519959"}, - {file = "grpcio-1.56.0-cp37-cp37m-win_amd64.whl", hash = "sha256:991224fd485e088d3cb5e34366053691a4848a6b7112b8f5625a411305c26691"}, - {file = "grpcio-1.56.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:c6f36621aabecbaff3e70c4d1d924c76c8e6a7ffec60c331893640a4af0a8037"}, - {file = "grpcio-1.56.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:1eadd6de258901929223f422ffed7f8b310c0323324caf59227f9899ea1b1674"}, - {file = "grpcio-1.56.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:72836b5a1d4f508ffbcfe35033d027859cc737972f9dddbe33fb75d687421e2e"}, - {file = "grpcio-1.56.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f92a99ab0c7772fb6859bf2e4f44ad30088d18f7c67b83205297bfb229e0d2cf"}, - {file = "grpcio-1.56.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa08affbf672d051cd3da62303901aeb7042a2c188c03b2c2a2d346fc5e81c14"}, - {file = "grpcio-1.56.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2db108b4c8e29c145e95b0226973a66d73ae3e3e7fae00329294af4e27f1c42"}, - {file = "grpcio-1.56.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8674fdbd28266d8efbcddacf4ec3643f76fe6376f73283fd63a8374c14b0ef7c"}, - {file = "grpcio-1.56.0-cp38-cp38-win32.whl", hash = "sha256:bd55f743e654fb050c665968d7ec2c33f03578a4bbb163cfce38024775ff54cc"}, - {file = "grpcio-1.56.0-cp38-cp38-win_amd64.whl", hash = "sha256:c63bc5ac6c7e646c296fed9139097ae0f0e63f36f0864d7ce431cce61fe0118a"}, - {file = "grpcio-1.56.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c0bc9dda550785d23f4f025be614b7faa8d0293e10811f0f8536cf50435b7a30"}, - {file = "grpcio-1.56.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:d596408bab632ec7b947761e83ce6b3e7632e26b76d64c239ba66b554b7ee286"}, - {file = "grpcio-1.56.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76b6e6e1ee9bda32e6e933efd61c512e9a9f377d7c580977f090d1a9c78cca44"}, - {file = "grpcio-1.56.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7beb84ebd0a3f732625124b73969d12b7350c5d9d64ddf81ae739bbc63d5b1ed"}, - {file = "grpcio-1.56.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83ec714bbbe9b9502177c842417fde39f7a267031e01fa3cd83f1ca49688f537"}, - {file = "grpcio-1.56.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4feee75565d1b5ab09cb3a5da672b84ca7f6dd80ee07a50f5537207a9af543a4"}, - {file = "grpcio-1.56.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b4638a796778329cc8e142e4f57c705adb286b3ba64e00b0fa91eeb919611be8"}, - {file = "grpcio-1.56.0-cp39-cp39-win32.whl", hash = "sha256:437af5a7673bca89c4bc0a993382200592d104dd7bf55eddcd141cef91f40bab"}, - {file = "grpcio-1.56.0-cp39-cp39-win_amd64.whl", hash = "sha256:4241a1c2c76e748023c834995cd916570e7180ee478969c2d79a60ce007bc837"}, - {file = "grpcio-1.56.0.tar.gz", hash = "sha256:4c08ee21b3d10315b8dc26f6c13917b20ed574cdbed2d2d80c53d5508fdcc0f2"}, -] - -[package.extras] -protobuf = ["grpcio-tools (>=1.56.0)"] - -[[package]] -name = "grpcio-tools" -version = "1.56.0" -======= - {file = "grpcio-1.53.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:752d2949b40e12e6ad3ed8cc552a65b54d226504f6b1fb67cab2ccee502cc06f"}, - {file = "grpcio-1.53.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:8a48fd3a7222be226bb86b7b413ad248f17f3101a524018cdc4562eeae1eb2a3"}, - {file = "grpcio-1.53.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:f3e837d29f0e1b9d6e7b29d569e2e9b0da61889e41879832ea15569c251c303a"}, - {file = "grpcio-1.53.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aef7d30242409c3aa5839b501e877e453a2c8d3759ca8230dd5a21cda029f046"}, - {file = "grpcio-1.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6f90698b5d1c5dd7b3236cd1fa959d7b80e17923f918d5be020b65f1c78b173"}, - {file = "grpcio-1.53.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a96c3c7f564b263c5d7c0e49a337166c8611e89c4c919f66dba7b9a84abad137"}, - {file = "grpcio-1.53.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ee81349411648d1abc94095c68cd25e3c2812e4e0367f9a9355be1e804a5135c"}, - {file = "grpcio-1.53.0-cp310-cp310-win32.whl", hash = "sha256:fdc6191587de410a184550d4143e2b24a14df495c86ca15e59508710681690ac"}, - {file = "grpcio-1.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:658ffe1e39171be00490db5bd3b966f79634ac4215a1eb9a85c6cd6783bf7f6e"}, - {file = "grpcio-1.53.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:1b172e6d497191940c4b8d75b53de82dc252e15b61de2951d577ec5b43316b29"}, - {file = "grpcio-1.53.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:82434ba3a5935e47908bc861ce1ebc43c2edfc1001d235d6e31e5d3ed55815f7"}, - {file = "grpcio-1.53.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:1c734a2d4843e4e14ececf5600c3c4750990ec319e1299db7e4f0d02c25c1467"}, - {file = "grpcio-1.53.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6a2ead3de3b2d53119d473aa2f224030257ef33af1e4ddabd4afee1dea5f04c"}, - {file = "grpcio-1.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a34d6e905f071f9b945cabbcc776e2055de1fdb59cd13683d9aa0a8f265b5bf9"}, - {file = "grpcio-1.53.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eaf8e3b97caaf9415227a3c6ca5aa8d800fecadd526538d2bf8f11af783f1550"}, - {file = "grpcio-1.53.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:da95778d37be8e4e9afca771a83424f892296f5dfb2a100eda2571a1d8bbc0dc"}, - {file = "grpcio-1.53.0-cp311-cp311-win32.whl", hash = "sha256:e4f513d63df6336fd84b74b701f17d1bb3b64e9d78a6ed5b5e8a198bbbe8bbfa"}, - {file = "grpcio-1.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:ddb2511fbbb440ed9e5c9a4b9b870f2ed649b7715859fd6f2ebc585ee85c0364"}, - {file = "grpcio-1.53.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:2a912397eb8d23c177d6d64e3c8bc46b8a1c7680b090d9f13a640b104aaec77c"}, - {file = "grpcio-1.53.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:55930c56b8f5b347d6c8c609cc341949a97e176c90f5cbb01d148d778f3bbd23"}, - {file = "grpcio-1.53.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6601d812105583948ab9c6e403a7e2dba6e387cc678c010e74f2d6d589d1d1b3"}, - {file = "grpcio-1.53.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c705e0c21acb0e8478a00e7e773ad0ecdb34bd0e4adc282d3d2f51ba3961aac7"}, - {file = "grpcio-1.53.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba074af9ca268ad7b05d3fc2b920b5fb3c083da94ab63637aaf67f4f71ecb755"}, - {file = "grpcio-1.53.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:14817de09317dd7d3fbc8272864288320739973ef0f4b56bf2c0032349da8cdf"}, - {file = "grpcio-1.53.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c7ad9fbedb93f331c2e9054e202e95cf825b885811f1bcbbdfdc301e451442db"}, - {file = "grpcio-1.53.0-cp37-cp37m-win_amd64.whl", hash = "sha256:dad5b302a4c21c604d88a5d441973f320134e6ff6a84ecef9c1139e5ffd466f6"}, - {file = "grpcio-1.53.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:fa8eaac75d3107e3f5465f2c9e3bbd13db21790c6e45b7de1756eba16b050aca"}, - {file = "grpcio-1.53.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:104a2210edd3776c38448b4f76c2f16e527adafbde171fc72a8a32976c20abc7"}, - {file = "grpcio-1.53.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:dbc1ba968639c1d23476f75c356e549e7bbf2d8d6688717dcab5290e88e8482b"}, - {file = "grpcio-1.53.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95952d3fe795b06af29bb8ec7bbf3342cdd867fc17b77cc25e6733d23fa6c519"}, - {file = "grpcio-1.53.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f144a790f14c51b8a8e591eb5af40507ffee45ea6b818c2482f0457fec2e1a2e"}, - {file = "grpcio-1.53.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0698c094688a2dd4c7c2f2c0e3e142cac439a64d1cef6904c97f6cde38ba422f"}, - {file = "grpcio-1.53.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6b6d60b0958be711bab047e9f4df5dbbc40367955f8651232bfdcdd21450b9ab"}, - {file = "grpcio-1.53.0-cp38-cp38-win32.whl", hash = "sha256:1948539ce78805d4e6256ab0e048ec793956d54787dc9d6777df71c1d19c7f81"}, - {file = "grpcio-1.53.0-cp38-cp38-win_amd64.whl", hash = "sha256:df9ba1183b3f649210788cf80c239041dddcb375d6142d8bccafcfdf549522cd"}, - {file = "grpcio-1.53.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:19caa5b7282a89b799e63776ff602bb39604f7ca98db6df27e2de06756ae86c3"}, - {file = "grpcio-1.53.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b5bd026ac928c96cc23149e6ef79183125542062eb6d1ccec34c0a37e02255e7"}, - {file = "grpcio-1.53.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:7dc8584ca6c015ad82e186e82f4c0fe977394588f66b8ecfc4ec873285314619"}, - {file = "grpcio-1.53.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2eddaae8af625e45b5c8500dcca1043264d751a6872cde2eda5022df8a336959"}, - {file = "grpcio-1.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5fb6f3d7824696c1c9f2ad36ddb080ba5a86f2d929ef712d511b4d9972d3d27"}, - {file = "grpcio-1.53.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8270d1dc2c98ab57e6dbf36fa187db8df4c036f04a398e5d5e25b4e01a766d70"}, - {file = "grpcio-1.53.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:976a7f24eb213e8429cab78d5e120500dfcdeb01041f1f5a77b17b9101902615"}, - {file = "grpcio-1.53.0-cp39-cp39-win32.whl", hash = "sha256:9c84a481451e7174f3a764a44150f93b041ab51045aa33d7b5b68b6979114e48"}, - {file = "grpcio-1.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:6beb84f83360ff29a3654f43f251ec11b809dcb5524b698d711550243debd289"}, - {file = "grpcio-1.53.0.tar.gz", hash = "sha256:a4952899b4931a6ba12951f9a141ef3e74ff8a6ec9aa2dc602afa40f63595e33"}, + {file = "grpcio-1.57.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:092fa155b945015754bdf988be47793c377b52b88d546e45c6a9f9579ac7f7b6"}, + {file = "grpcio-1.57.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2f7349786da979a94690cc5c2b804cab4e8774a3cf59be40d037c4342c906649"}, + {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:82640e57fb86ea1d71ea9ab54f7e942502cf98a429a200b2e743d8672171734f"}, + {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40b72effd4c789de94ce1be2b5f88d7b9b5f7379fe9645f198854112a6567d9a"}, + {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f708a6a17868ad8bf586598bee69abded4996b18adf26fd2d91191383b79019"}, + {file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:60fe15288a0a65d5c1cb5b4a62b1850d07336e3ba728257a810317be14f0c527"}, + {file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6907b1cf8bb29b058081d2aad677b15757a44ef2d4d8d9130271d2ad5e33efca"}, + {file = "grpcio-1.57.0-cp310-cp310-win32.whl", hash = "sha256:57b183e8b252825c4dd29114d6c13559be95387aafc10a7be645462a0fc98bbb"}, + {file = "grpcio-1.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:7b400807fa749a9eb286e2cd893e501b110b4d356a218426cb9c825a0474ca56"}, + {file = "grpcio-1.57.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:c6ebecfb7a31385393203eb04ed8b6a08f5002f53df3d59e5e795edb80999652"}, + {file = "grpcio-1.57.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:00258cbe3f5188629828363ae8ff78477ce976a6f63fb2bb5e90088396faa82e"}, + {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:23e7d8849a0e58b806253fd206ac105b328171e01b8f18c7d5922274958cc87e"}, + {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5371bcd861e679d63b8274f73ac281751d34bd54eccdbfcd6aa00e692a82cd7b"}, + {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aed90d93b731929e742967e236f842a4a2174dc5db077c8f9ad2c5996f89f63e"}, + {file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe752639919aad9ffb0dee0d87f29a6467d1ef764f13c4644d212a9a853a078d"}, + {file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fada6b07ec4f0befe05218181f4b85176f11d531911b64c715d1875c4736d73a"}, + {file = "grpcio-1.57.0-cp311-cp311-win32.whl", hash = "sha256:bb396952cfa7ad2f01061fbc7dc1ad91dd9d69243bcb8110cf4e36924785a0fe"}, + {file = "grpcio-1.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:e503cb45ed12b924b5b988ba9576dc9949b2f5283b8e33b21dcb6be74a7c58d0"}, + {file = "grpcio-1.57.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:fd173b4cf02b20f60860dc2ffe30115c18972d7d6d2d69df97ac38dee03be5bf"}, + {file = "grpcio-1.57.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:d7f8df114d6b4cf5a916b98389aeaf1e3132035420a88beea4e3d977e5f267a5"}, + {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:76c44efa4ede1f42a9d5b2fed1fe9377e73a109bef8675fb0728eb80b0b8e8f2"}, + {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4faea2cfdf762a664ab90589b66f416274887641ae17817de510b8178356bf73"}, + {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c60b83c43faeb6d0a9831f0351d7787a0753f5087cc6fa218d78fdf38e5acef0"}, + {file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b363bbb5253e5f9c23d8a0a034dfdf1b7c9e7f12e602fc788c435171e96daccc"}, + {file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f1fb0fd4a1e9b11ac21c30c169d169ef434c6e9344ee0ab27cfa6f605f6387b2"}, + {file = "grpcio-1.57.0-cp37-cp37m-win_amd64.whl", hash = "sha256:34950353539e7d93f61c6796a007c705d663f3be41166358e3d88c45760c7d98"}, + {file = "grpcio-1.57.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:871f9999e0211f9551f368612460442a5436d9444606184652117d6a688c9f51"}, + {file = "grpcio-1.57.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:a8a8e560e8dbbdf29288872e91efd22af71e88b0e5736b0daf7773c1fecd99f0"}, + {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2313b124e475aa9017a9844bdc5eafb2d5abdda9d456af16fc4535408c7d6da6"}, + {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4098b6b638d9e0ca839a81656a2fd4bc26c9486ea707e8b1437d6f9d61c3941"}, + {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e5b58e32ae14658085c16986d11e99abd002ddbf51c8daae8a0671fffb3467f"}, + {file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0f80bf37f09e1caba6a8063e56e2b87fa335add314cf2b78ebf7cb45aa7e3d06"}, + {file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5b7a4ce8f862fe32b2a10b57752cf3169f5fe2915acfe7e6a1e155db3da99e79"}, + {file = "grpcio-1.57.0-cp38-cp38-win32.whl", hash = "sha256:9338bacf172e942e62e5889b6364e56657fbf8ac68062e8b25c48843e7b202bb"}, + {file = "grpcio-1.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:e1cb52fa2d67d7f7fab310b600f22ce1ff04d562d46e9e0ac3e3403c2bb4cc16"}, + {file = "grpcio-1.57.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fee387d2fab144e8a34e0e9c5ca0f45c9376b99de45628265cfa9886b1dbe62b"}, + {file = "grpcio-1.57.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b53333627283e7241fcc217323f225c37783b5f0472316edcaa4479a213abfa6"}, + {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f19ac6ac0a256cf77d3cc926ef0b4e64a9725cc612f97228cd5dc4bd9dbab03b"}, + {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fdf04e402f12e1de8074458549337febb3b45f21076cc02ef4ff786aff687e"}, + {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5613a2fecc82f95d6c51d15b9a72705553aa0d7c932fad7aed7afb51dc982ee5"}, + {file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b670c2faa92124b7397b42303e4d8eb64a4cd0b7a77e35a9e865a55d61c57ef9"}, + {file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a635589201b18510ff988161b7b573f50c6a48fae9cb567657920ca82022b37"}, + {file = "grpcio-1.57.0-cp39-cp39-win32.whl", hash = "sha256:d78d8b86fcdfa1e4c21f8896614b6cc7ee01a2a758ec0c4382d662f2a62cf766"}, + {file = "grpcio-1.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:20ec6fc4ad47d1b6e12deec5045ec3cd5402d9a1597f738263e98f490fe07056"}, + {file = "grpcio-1.57.0.tar.gz", hash = "sha256:4b089f7ad1eb00a104078bab8015b0ed0ebcb3b589e527ab009c53893fd4e613"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.53.0)"] +protobuf = ["grpcio-tools (>=1.57.0)"] [[package]] name = "grpcio-tools" -version = "1.53.0" ->>>>>>> second-repo/main +version = "1.57.0" description = "Protobuf code generator for gRPC" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD - {file = "grpcio-tools-1.56.0.tar.gz", hash = "sha256:39f5877cea514b3da9f2683dfb3ffb45ef47b05f4ff39c287d7d61c5057f48b8"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:cdbae7312e6d132d38ec2c1611b8cafb783e0416cc5c6deae04efde5f16fb190"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:5f5c416b88d76fbdb548cfee0486928748816b700ece6e591006e5b1dc67598f"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:23e2ef1dc6a9bf766f091e2c52a68e54d0aff3548f94562e61fb0ac3874d514a"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8870ab60f8a76b4a7e43184ee03d28112b976d83c43d41cec821f47b3a297da2"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e59ab6c0bf4a8bb975553ad578d4425bd192775ae384f9406d77d31ad00f6efe"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b309659534b5d930f9ab6d521670c2dd86cb6ef7f47f37f73f96557e2ec13a49"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8115b416ea2cad8a87dc3aadfaf26da684e003c3770b12e7219b462505bb5b85"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-win32.whl", hash = "sha256:e4cb62a521efbca4cb1ad50233aa400574b3daaf6eb26707d661a0afe8191d92"}, - {file = "grpcio_tools-1.56.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d59009ed52220eb2d62f5cefa4e58dec930fb92fab27bb390c4cf1d360ac7e1"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:cd69107705794e815a8b262722c6fea995911cb1dfc1310abf63b476165335d6"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:2d1ee9e13ce135a6ed451b428ef14af131dc7df2551a5344ff4f8aee2d9fab99"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:142530b9fdfabe04f0c7e5dacd45b6c419d39704fa439cc0aabf73ea0d8f916d"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b7a4eb5003a29eecd71707589f93ae7e8fa2e681366a811b3f86695055d8666"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa6d9bdd75d3625dae38372b43696e159c10aa98719b4302b1e94f1ff7878d47"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c43b4fe8c8df4c52d3106bba2cf427f0e46bbebb80e127fbbc3134db0fead7be"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:168940a4a955b6c65da978dbf62e1c36e3a311bb27f649fd201a228e2583a6d4"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-win32.whl", hash = "sha256:3a4b06169493f9454a7f2516c5d41b566d9734e553bbc505f2a7837f7f4a2df1"}, - {file = "grpcio_tools-1.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:1bd361fcc967c21672ba855fc77ea0e7afa51664033a746df96545f84edc4670"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e6bcb194b81e372411494d8ed69fab89aa3452b7275fce4f7917fbe7b04fb72"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:02b23a12b91287ebea14b3685735d1d675e77c3cd365ec1771c3e9afbeba1ec6"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:80d75856f8ec949847386ad2f56a460f21c63bf82ce99ca5b6aa512c0b875fb1"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cffff0b4af80285fa49637d69b69d640eb775dc74b23635e4de5faad9e7e744"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3de6c08b545920a39b31ed13305f946c00b19ac1b13d26119f111b6360f22ccf"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:128bb13fe9a2681eeb08175f5fbc8e2d8953d7d0dd240e96f9244b9d2547a1aa"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b57f7f01eafbfe3a293f2efffb675774dbe4074c4627975ec4dc4aa5766801fb"}, - {file = "grpcio_tools-1.56.0-cp37-cp37m-win_amd64.whl", hash = "sha256:282176066fb082ad21c403b84f9d6b440a20482e6f52b83bb2adf54d6fdcae9f"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:d9b8d1c42854d3433c058795f52b1418b53dd8c1e9811fecb1312202e803a2c5"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:accf713f51da74b1a18aa4b31df0ab135510704661f735a938081777b79a4c25"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:ac33fd2d02d24101ea389be8e05b928acb58be56403d4ebc3aecfab473fa4a25"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4acdc7b957abfd76581717f0ac8e4408e0a85b7d0ac8d2cdf4d964f16926b897"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79291bfb1fe5f21d99f4839f43d3c5d44c5402c830a24dbb2811d785dd21264b"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0a8767e4de0f573c678313c5de075ac0e163a192bb135018e45015a22f234387"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:96fe2f7f5805d88cb7f2e3e3502550b2883dfab0f9efcf3cbd444942cf2ee1da"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-win32.whl", hash = "sha256:21cf32ccffd4f1800b0dcdf58aa1fc7f626795c9da784c3d817c944edcf2d3ae"}, - {file = "grpcio_tools-1.56.0-cp38-cp38-win_amd64.whl", hash = "sha256:f3ab1a9fad636302f7307d143f64a9fbd11bc041652bf53bb016006e9a5ca820"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:8989d363ac1996238fee61c8f5663f15a8fc362cb1e758c4a686b76cb457cd70"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:11cdd9cbf0c09c3a761c6f59dfd7128104be7cd393334efe386d4fc3f990ee1a"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5fd4c005a4afec16578849bc522ddf3298d6d499b3d37bf51314b086c714cdd5"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7302acaa07cf4966c926fcd6a60c8d30a697f730c38168bf83e1519b464115b"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1c43d185ebf904c3deec23c36ca2ba4e95db999cf00fc8f85eda4551622a26"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b12bb8c1d408ae40e4c806a3a8ebda2d107310e46696e1da13d0dc3f91fbd19d"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:781cf09e4d5c9288708f6ec9c3eae64d9d5a0f4c46c7ebe70ebb7ab4f6384789"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-win32.whl", hash = "sha256:c62f07452dee3f1ed23aeaef821797c5e516f79535e97fe6a6b0a0ee8db1cc91"}, - {file = "grpcio_tools-1.56.0-cp39-cp39-win_amd64.whl", hash = "sha256:7f063443870650e55012fdb3a58ff4ce5f4042b81dad6b749333ee8146157511"}, + {file = "grpcio-tools-1.57.0.tar.gz", hash = "sha256:2f16130d869ce27ecd623194547b649dd657333ec7e8644cc571c645781a9b85"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:4fb8a8468031f858381a576078924af364a08833d8f8f3237018252c4573a802"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:35bf0dad8a3562043345236c26d0053a856fb06c04d7da652f2ded914e508ae7"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:ec9aab2fb6783c7fc54bc28f58eb75f1ca77594e6b0fd5e5e7a8114a95169fe0"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf5fc0a1c23f8ea34b408b72fb0e90eec0f404ad4dba98e8f6da3c9ce34e2ed"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26e69d08a515554e0cfe1ec4d31568836f4b17f0ff82294f957f629388629eb9"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c39a3656576b6fdaaf28abe0467f7a7231df4230c1bee132322dbc3209419e7f"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f64f8ab22d27d4a5693310748d35a696061c3b5c7b8c4fb4ab3b4bc1068b6b56"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-win32.whl", hash = "sha256:d2a134756f4db34759a5cc7f7e43f7eb87540b68d1cca62925593c6fb93924f7"}, + {file = "grpcio_tools-1.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a3d60fb8d46ede26c1907c146561b3a9caa20a7aff961bc661ef8226f85a2e9"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:aac98ecad8f7bd4301855669d42a5d97ef7bb34bec2b1e74c7a0641d47e313cf"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:cdd020cb68b51462983b7c2dfbc3eb6ede032b8bf438d4554df0c3f08ce35c76"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:f54081b08419a39221cd646363b5708857c696b3ad4784f1dcf310891e33a5f7"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed85a0291fff45b67f2557fe7f117d3bc7af8b54b8619d27bf374b5c8b7e3ca2"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e868cd6feb3ef07d4b35be104fe1fd0657db05259ff8f8ec5e08f4f89ca1191d"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:dfb6f6120587b8e228a3cae5ee4985b5bdc18501bad05c49df61965dfc9d70a9"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4a7ad7f328e28fc97c356d0f10fb10d8b5151bb65aa7cf14bf8084513f0b7306"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-win32.whl", hash = "sha256:9867f2817b1a0c93c523f89ac6c9d8625548af4620a7ce438bf5a76e23327284"}, + {file = "grpcio_tools-1.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:1f9e917a9f18087f6c14b4d4508fb94fca5c2f96852363a89232fb9b2124ac1f"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:9f2aefa8a37bd2c4db1a3f1aca11377e2766214520fb70e67071f4ff8d8b0fa5"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:850cbda0ec5d24c39e7215ede410276040692ca45d105fbbeada407fa03f0ac0"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6fa52972c9647876ea35f6dc2b51002a74ed900ec7894586cbb2fe76f64f99de"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0eea89d7542719594e50e2283f51a072978b953e8b3e9fd7c59a2c762d4c1"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3da5240211252fc70a6451fe00c143e2ab2f7bfc2445695ad2ed056b8e48d96"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a0256f8786ac9e4db618a1aa492bb3472569a0946fd3ee862ffe23196323da55"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c026bdf5c1366ce88b7bbe2d8207374d675afd3fd911f60752103de3da4a41d2"}, + {file = "grpcio_tools-1.57.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9053c2f655589545be08b9d6a673e92970173a4bf11a4b9f18cd6e9af626b587"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:81ec4dbb696e095057b2528d11a8da04be6bbe2b967fa07d4ea9ba6354338cbf"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:495e2946406963e0b9f063f76d5af0f2a19517dac2b367b5b044432ac9194296"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:7b46fc6aa8eb7edd18cafcd21fd98703cb6c09e46b507de335fca7f0161dfccb"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb81ff861692111fa81bd85f64584e624cb4013bd66fbce8a209b8893f5ce398"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a42dc220eb5305f470855c9284f4c8e85ae59d6d742cd07946b0cbe5e9ca186"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90d10d9038ba46a595a223a34f136c9230e3d6d7abc2433dbf0e1c31939d3a8b"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5bc3e6d338aefb052e19cedabe00452be46d0c10a4ed29ee77abb00402e438fe"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-win32.whl", hash = "sha256:34b36217b17b5bea674a414229913e1fd80ede328be51e1b531fcc62abd393b0"}, + {file = "grpcio_tools-1.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbde4004a0688400036342ff73e3706e8940483e2871547b1354d59e93a38277"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:784574709b9690dc28696617ea69352e2132352fdfc9bc89afa8e39f99ae538e"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:85ac4e62eb44428cde025fd9ab7554002315fc7880f791c553fc5a0015cc9931"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:dc771d4db5701f280957bbcee91745e0686d00ed1c6aa7e05ba30a58b02d70a1"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3ac06703c412f8167a9062eaf6099409967e33bf98fa5b02be4b4689b6bdf39"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02d78c034109f46032c7217260066d49d41e6bcaf588fa28fa40fe2f83445347"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2db25f15ed44327f2e02d0c4fe741ac966f9500e407047d8a7c7fccf2df65616"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b417c97936d94874a3ce7ed8deab910f2233e3612134507cfee4af8735c38a6"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-win32.whl", hash = "sha256:f717cce5093e6b6049d9ea6d12fdf3658efdb1a80772f7737db1f8510b876df6"}, + {file = "grpcio_tools-1.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:1c0e8a1a32973a5d59fbcc19232f925e5c48116e9411f788033a31c5ca5130b4"}, ] [package.dependencies] -grpcio = ">=1.56.0" -======= - {file = "grpcio-tools-1.53.0.tar.gz", hash = "sha256:925efff2d63ca3266f93c924ffeba5d496f16a8ccbe125fa0d18acf47cc5fa88"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:41b859cf943256debba1e7b921e3689c89f95495b65f7ad226c4f0e38edf8ee4"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:17c557240f7fbe1886dcfb5f3ba79740ecb65fe3b93061e64b8f4dfc6a6a5dc5"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:6afffd7e97e5bddc63b3ce9abe912b9adb704a36ba86d4406be94426734b97c2"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f55e2c13620271b7f5a81a489a188d6e34a24da8885d46f1566f0e798cb59e6f"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bd4c732d8d7a736e787b5d0963d4195267fc856e1d313d4532d1625e19a0e4a"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:99ecefb6b66e9fe41468a70ee2f05da2eb9c7bf63867fb9ff07f7dd90ea813ae"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7754d6466191d327a0eef364ad5b863477a8fcc12953adc06b30b8e470c70e4a"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-win32.whl", hash = "sha256:f31c549d793a0e72c044f724b3373141d2aa9970fe97b1c2cfaa7ea44002b9aa"}, - {file = "grpcio_tools-1.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4173b95e2c29a5145c806d16945ce1e5b38a11c7eb6ab1a6d74afc0a2ce47d9"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:613a84ebd1881635370c12503f2b15b37332a53fbac32904c94ac4c0c10f0a2a"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:af686b83bc6b5c1f1591c9f49183717974047de9546adcf5e09a18781b550c96"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:3cc832e8297e9437bc2b137fe815c8ba1d9af6ffdd76c5c6d7f911bf8e1b0f45"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39d0a254de49d852f5fe9f9df0a45b2ae66bc04e2d9ee1d6d2c0ba1e70fac91a"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7062109553ec1873c5c09cc379b8ae0aa76a2d6d6aae97759b97787b93fa9786"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7728407b1e89fb1473b86152fc33be00f1a25a5aa3264245521f05cbbef9d817"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2758ea125442bc81251267fc9c28f65555a571f6a0afda4d71a6e7d669347095"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-win32.whl", hash = "sha256:8940d59fca790f1bd45785d0661c3a8c081231c9f8049d7fbf6c6c00737e43da"}, - {file = "grpcio_tools-1.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:c2cff79be5a06d63e9a6a7e38f8f160ade21517386eabe27afacef65a8531358"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:d646d65fafbf70a57416493e719a0df7ffa0772133266cfe1b2b72e072ae64a2"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:7da0fc185735050d8240b1d74c4667a02baf1b4fa379a5fc05d1fc067eeba596"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:2be17265c0f070efd625683cef986e07dbc495103fcc719009ff2f6988003166"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4701d48f649443f1101a24d85e9d5ac13346ccac7781e243f49491328e172266"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b54c64d85bea5c3a3d895454878c7d6bed5cbb80dc3cafcd75dc1e78300d8c95"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7152045190e9bd665d1feaeaef931d82c75cacce2b116ab150befa90855de3d0"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e18292123c86975d0aa47f1bcb176393640dcc23912e9f3a2247f1eff81ac8e8"}, - {file = "grpcio_tools-1.53.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b1b76b6ab5c24e44b15d6a7df6c1b81c3099a54b82d41a3ce96e73a2e6a5081c"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:e76e8dfe6fe4e61ce3049e9d56c0d806d0d3edc28aa32117d1b17f387469c52e"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:4c6acaca09cfcd59850e27bd138df9d01c0686c42a5412aa6a92141c15316b1e"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:76898c1dadf8630a75a40b5a89ab38e326f1288dcfde3413cdfa7a58e149c987"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b47f8b1bd3af2fb25548b625ad9c3659da30fe83c06f462f357c754f49b71ae"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2faad4b6362e7ff3ae43ef2d51dfce0a3bc32cf52469e88568c3f65cae377d5"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:830261fe08541f0fd2dd5035264df2b91012988f37aa1d80a0b4ee6404dc25ae"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4be32c694c760f3281555089f7aed7d48ca7ea4094115a08b5fc895e17d7e62e"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-win32.whl", hash = "sha256:4605db5a5828205d7fa33a5de9e00723bd037709e74e15c028b9dcec2339b7bc"}, - {file = "grpcio_tools-1.53.0-cp38-cp38-win_amd64.whl", hash = "sha256:0229e6cd442915192b8f8ee2e7e1c8b9986c878bc4dd8be3539f3be35f1b8282"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:ad0c20688a650e731e8328a7a08899c433a59bfc995a7afcf715b5ad9eca9e7b"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:a8c3e30c531969c62a5a219be414277b269c1be9a76bcd6948571868894e19b2"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:326c67b35be69409a88632e6145032d53b8b8141634e9cbcd27fa8f9015a112c"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:102b6d323d7cef7ac29683f949ec66885b417c06df6059f6a88d07c5556c2592"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:861f8634cca3ca5bb5336ba16cc78291dba3e7fcadedff195bfdeb433f2c29f2"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c9a9e1da1868349eba401e9648eac19132700942c475adcc97b6938bf4bf0182"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ccf7313e5bee13f2f86d12741489f3ed8c901d6b463dff2604191cd4ff518abb"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-win32.whl", hash = "sha256:65b77532bb8f6ab1bfbdd2ac0788626a6c05b227f4722d3bbc2c54258e49c3e5"}, - {file = "grpcio_tools-1.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:7c0ede22796259e83aa1f108038513e86672b2892d3654f94415e3930b74b871"}, -] - -[package.dependencies] -grpcio = ">=1.53.0" ->>>>>>> second-repo/main +grpcio = ">=1.57.0" protobuf = ">=4.21.6,<5.0dev" setuptools = "*" @@ -2180,16 +1420,11 @@ socks = ["socksio (==1.*)"] [[package]] name = "httptools" -<<<<<<< HEAD version = "0.6.0" -======= -version = "0.5.0" ->>>>>>> second-repo/main description = "A collection of framework independent HTTP protocol utils." optional = false python-versions = ">=3.5.0" files = [ -<<<<<<< HEAD {file = "httptools-0.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:818325afee467d483bfab1647a72054246d29f9053fd17cc4b86cda09cc60339"}, {file = "httptools-0.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72205730bf1be875003692ca54a4a7c35fac77b4746008966061d9d41a61b0f5"}, {file = "httptools-0.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33eb1d4e609c835966e969a31b1dedf5ba16b38cab356c2ce4f3e33ffa94cad3"}, @@ -2225,49 +1460,6 @@ files = [ {file = "httptools-0.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:dea66d94e5a3f68c5e9d86e0894653b87d952e624845e0b0e3ad1c733c6cc75d"}, {file = "httptools-0.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:23b09537086a5a611fad5696fc8963d67c7e7f98cb329d38ee114d588b0b74cd"}, {file = "httptools-0.6.0.tar.gz", hash = "sha256:9fc6e409ad38cbd68b177cd5158fc4042c796b82ca88d99ec78f07bed6c6b796"}, -======= - {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f470c79061599a126d74385623ff4744c4e0f4a0997a353a44923c0b561ee51"}, - {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e90491a4d77d0cb82e0e7a9cb35d86284c677402e4ce7ba6b448ccc7325c5421"}, - {file = "httptools-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d2357f791b12d86faced7b5736dea9ef4f5ecdc6c3f253e445ee82da579449"}, - {file = "httptools-0.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f90cd6fd97c9a1b7fe9215e60c3bd97336742a0857f00a4cb31547bc22560c2"}, - {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5230a99e724a1bdbbf236a1b58d6e8504b912b0552721c7c6b8570925ee0ccde"}, - {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a47a34f6015dd52c9eb629c0f5a8a5193e47bf2a12d9a3194d231eaf1bc451a"}, - {file = "httptools-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:24bb4bb8ac3882f90aa95403a1cb48465de877e2d5298ad6ddcfdebec060787d"}, - {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e67d4f8734f8054d2c4858570cc4b233bf753f56e85217de4dfb2495904cf02e"}, - {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e5eefc58d20e4c2da82c78d91b2906f1a947ef42bd668db05f4ab4201a99f49"}, - {file = "httptools-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0297822cea9f90a38df29f48e40b42ac3d48a28637368f3ec6d15eebefd182f9"}, - {file = "httptools-0.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:557be7fbf2bfa4a2ec65192c254e151684545ebab45eca5d50477d562c40f986"}, - {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:54465401dbbec9a6a42cf737627fb0f014d50dc7365a6b6cd57753f151a86ff0"}, - {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4d9ebac23d2de960726ce45f49d70eb5466725c0087a078866043dad115f850f"}, - {file = "httptools-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:e8a34e4c0ab7b1ca17b8763613783e2458e77938092c18ac919420ab8655c8c1"}, - {file = "httptools-0.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f659d7a48401158c59933904040085c200b4be631cb5f23a7d561fbae593ec1f"}, - {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1616b3ba965cd68e6f759eeb5d34fbf596a79e84215eeceebf34ba3f61fdc7"}, - {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3625a55886257755cb15194efbf209584754e31d336e09e2ffe0685a76cb4b60"}, - {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:72ad589ba5e4a87e1d404cc1cb1b5780bfcb16e2aec957b88ce15fe879cc08ca"}, - {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:850fec36c48df5a790aa735417dca8ce7d4b48d59b3ebd6f83e88a8125cde324"}, - {file = "httptools-0.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f222e1e9d3f13b68ff8a835574eda02e67277d51631d69d7cf7f8e07df678c86"}, - {file = "httptools-0.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3cb8acf8f951363b617a8420768a9f249099b92e703c052f9a51b66342eea89b"}, - {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550059885dc9c19a072ca6d6735739d879be3b5959ec218ba3e013fd2255a11b"}, - {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a04fe458a4597aa559b79c7f48fe3dceabef0f69f562daf5c5e926b153817281"}, - {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d0c1044bce274ec6711f0770fd2d5544fe392591d204c68328e60a46f88843b"}, - {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c6eeefd4435055a8ebb6c5cc36111b8591c192c56a95b45fe2af22d9881eee25"}, - {file = "httptools-0.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b65be160adcd9de7a7e6413a4966665756e263f0d5ddeffde277ffeee0576a5"}, - {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fe9c766a0c35b7e3d6b6939393c8dfdd5da3ac5dec7f971ec9134f284c6c36d6"}, - {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85b392aba273566c3d5596a0a490978c085b79700814fb22bfd537d381dd230c"}, - {file = "httptools-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5e3088f4ed33947e16fd865b8200f9cfae1144f41b64a8cf19b599508e096bc"}, - {file = "httptools-0.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c2a56b6aad7cc8f5551d8e04ff5a319d203f9d870398b94702300de50190f63"}, - {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b571b281a19762adb3f48a7731f6842f920fa71108aff9be49888320ac3e24d"}, - {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa47ffcf70ba6f7848349b8a6f9b481ee0f7637931d91a9860a1838bfc586901"}, - {file = "httptools-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:bede7ee075e54b9a5bde695b4fc8f569f30185891796b2e4e09e2226801d09bd"}, - {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:64eba6f168803a7469866a9c9b5263a7463fa8b7a25b35e547492aa7322036b6"}, - {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b098e4bb1174096a93f48f6193e7d9aa7071506a5877da09a783509ca5fff42"}, - {file = "httptools-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9423a2de923820c7e82e18980b937893f4aa8251c43684fa1772e341f6e06887"}, - {file = "httptools-0.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1b7becf7d9d3ccdbb2f038f665c0f4857e08e1d8481cbcc1a86a0afcfb62b2"}, - {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:50d4613025f15f4b11f1c54bbed4761c0020f7f921b95143ad6d58c151198142"}, - {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ffce9d81c825ac1deaa13bc9694c0562e2840a48ba21cfc9f3b4c922c16f372"}, - {file = "httptools-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:1af91b3650ce518d226466f30bbba5b6376dbd3ddb1b2be8b0658c6799dd450b"}, - {file = "httptools-0.5.0.tar.gz", hash = "sha256:295874861c173f9101960bba332429bb77ed4dcd8cdf5cee9922eb00e4f6bc09"}, ->>>>>>> second-repo/main ] [package.extras] @@ -2297,6 +1489,38 @@ cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +[[package]] +name = "huggingface-hub" +version = "0.16.4" +description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "huggingface_hub-0.16.4-py3-none-any.whl", hash = "sha256:0d3df29932f334fead024afc7cb4cc5149d955238b8b5e42dcf9740d6995a349"}, + {file = "huggingface_hub-0.16.4.tar.gz", hash = "sha256:608c7d4f3d368b326d1747f91523dbd1f692871e8e2e7a4750314a2dd8b63e14"}, +] + +[package.dependencies] +filelock = "*" +fsspec = "*" +packaging = ">=20.9" +pyyaml = ">=5.1" +requests = "*" +tqdm = ">=4.42.1" +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "black (>=23.1,<24.0)", "gradio", "jedi", "mypy (==0.982)", "numpy", "pydantic", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "ruff (>=0.0.241)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "urllib3 (<2.0)"] +cli = ["InquirerPy (==0.3.4)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "black (>=23.1,<24.0)", "gradio", "jedi", "mypy (==0.982)", "numpy", "pydantic", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "ruff (>=0.0.241)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "urllib3 (<2.0)"] +fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] +inference = ["aiohttp", "pydantic"] +quality = ["black (>=23.1,<24.0)", "mypy (==0.982)", "ruff (>=0.0.241)"] +tensorflow = ["graphviz", "pydot", "tensorflow"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +torch = ["torch"] +typing = ["pydantic", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3"] + [[package]] name = "humanfriendly" version = "10.0" @@ -2335,7 +1559,6 @@ files = [ [[package]] name = "importlib-metadata" -<<<<<<< HEAD version = "6.8.0" description = "Read metadata from Python packages" optional = false @@ -2343,15 +1566,6 @@ python-versions = ">=3.8" files = [ {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, -======= -version = "6.6.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, - {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -2360,11 +1574,7 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -<<<<<<< HEAD testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] -======= -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] ->>>>>>> second-repo/main [[package]] name = "iniconfig" @@ -2404,7 +1614,6 @@ six = "*" [[package]] name = "jaraco-classes" -<<<<<<< HEAD version = "3.3.0" description = "Utility functions for Python class constructs" optional = false @@ -2412,28 +1621,14 @@ python-versions = ">=3.8" files = [ {file = "jaraco.classes-3.3.0-py3-none-any.whl", hash = "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb"}, {file = "jaraco.classes-3.3.0.tar.gz", hash = "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621"}, -======= -version = "3.2.3" -description = "Utility functions for Python class constructs" -optional = false -python-versions = ">=3.7" -files = [ - {file = "jaraco.classes-3.2.3-py3-none-any.whl", hash = "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158"}, - {file = "jaraco.classes-3.2.3.tar.gz", hash = "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a"}, ->>>>>>> second-repo/main ] [package.dependencies] more-itertools = "*" [package.extras] -<<<<<<< HEAD docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] -======= -docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] ->>>>>>> second-repo/main [[package]] name = "jeepney" @@ -2450,9 +1645,29 @@ files = [ test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] trio = ["async_generator", "trio"] +[[package]] +name = "kdbai-client" +version = "0.0.0" +description = "KDB.AI Client for Python" +optional = false +python-versions = "^3.8" +files = [] +develop = false + +[package.dependencies] +pandas = ">=1.5.0" +pykx = ">=1.6.0" + +[package.extras] +lint = ["mypy", "mypy-gitlab-code-quality"] +test = ["pytest (>=7.3.2,<8.0.0)", "pytest-cov (>=4.0.0,<5.0.0)", "pytest-mock"] + +[package.source] +type = "directory" +url = "../vector/kdbai-python-client" + [[package]] name = "keyring" -<<<<<<< HEAD version = "24.2.0" description = "Store and access your passwords safely." optional = false @@ -2460,15 +1675,6 @@ python-versions = ">=3.8" files = [ {file = "keyring-24.2.0-py3-none-any.whl", hash = "sha256:4901caaf597bfd3bbd78c9a0c7c4c29fcd8310dab2cffefe749e916b6527acd6"}, {file = "keyring-24.2.0.tar.gz", hash = "sha256:ca0746a19ec421219f4d713f848fa297a661a8a8c1504867e55bfb5e09091509"}, -======= -version = "23.13.1" -description = "Store and access your passwords safely." -optional = false -python-versions = ">=3.7" -files = [ - {file = "keyring-23.13.1-py3-none-any.whl", hash = "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd"}, - {file = "keyring-23.13.1.tar.gz", hash = "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -2480,100 +1686,32 @@ SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} [package.extras] completion = ["shtab"] -<<<<<<< HEAD docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [[package]] name = "langchain" -version = "0.0.270" -======= -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[[package]] -name = "langchain" -version = "0.0.187" ->>>>>>> second-repo/main +version = "0.0.70" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ -<<<<<<< HEAD - {file = "langchain-0.0.270-py3-none-any.whl", hash = "sha256:ea1ee4bcf297871ea4fcdabd338cb90d9a767bf0e60501b7e6540eaf6ea31a9c"}, - {file = "langchain-0.0.270.tar.gz", hash = "sha256:9777af5dd7e2901e4d9e00e917c05475d8f8e6772dea0e743c2cfd1e16092fbc"}, -======= - {file = "langchain-0.0.187-py3-none-any.whl", hash = "sha256:33c6cdbc99e6dda6f1cfc3bb4a8b099a7631e1a4e4c2f3121e0d6fac880d9b3b"}, - {file = "langchain-0.0.187.tar.gz", hash = "sha256:acd840358d0b47c60291c517a7affe9c2db70b70a5c8b2e5edc744889facb672"}, ->>>>>>> second-repo/main + {file = "langchain-0.0.70-py3-none-any.whl", hash = "sha256:55352197c65072d13058715b75a6e9f966d23234086323cddacc25e309ff3bbd"}, + {file = "langchain-0.0.70.tar.gz", hash = "sha256:53c197248a3f789cc424aa812233ebe2ecadfef6a00c78a2a805f18c723fb475"}, ] [package.dependencies] -aiohttp = ">=3.8.3,<4.0.0" -async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -dataclasses-json = ">=0.5.7,<0.6.0" -<<<<<<< HEAD -langsmith = ">=0.0.21,<0.1.0" -numexpr = ">=2.8.4,<3.0.0" numpy = ">=1,<2" -pydantic = ">=1,<3" -PyYAML = ">=5.3" -======= -numexpr = ">=2.8.4,<3.0.0" -numpy = ">=1,<2" -openapi-schema-pydantic = ">=1.2,<2.0" pydantic = ">=1,<2" -PyYAML = ">=5.4.1" ->>>>>>> second-repo/main +PyYAML = ">=6,<7" requests = ">=2,<3" -SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +SQLAlchemy = ">=1,<2" [package.extras] -<<<<<<< HEAD -all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "amadeus (>=8.1.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.9,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clarifai (>=9.1.0)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=4,<5)", "deeplake (>=3.6.8,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.6,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "libdeeplake (>=0.0.60,<0.0.61)", "librosa (>=0.10.0.post2,<0.11.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "marqo (>=0.11.0,<0.12.0)", "momento (>=1.5.0,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "python-arango (>=7.5.9,<8.0.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.3.1,<2.0.0)", "rdflib (>=6.3.2,<7.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.4.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] -azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b6)", "openai (>=0,<1)"] -clarifai = ["clarifai (>=9.1.0)"] -cohere = ["cohere (>=4,<5)"] -docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] -embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["amazon-textract-caller (<2)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.0.7,<0.0.8)", "chardet (>=5.1.0,<6.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "openai (>=0,<1)", "openapi-schema-pydantic (>=1.2,<2.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tqdm (>=4.48.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] -javascript = ["esprima (>=4.0.1,<5.0.0)"] -llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] -openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.4.0)"] -qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] -text-helpers = ["chardet (>=5.1.0,<6.0.0)"] - -[[package]] -name = "langsmith" -version = "0.0.25" -description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." -optional = false -python-versions = ">=3.8.1,<4.0" -files = [ - {file = "langsmith-0.0.25-py3-none-any.whl", hash = "sha256:d595435ad21fa6077550d7c85472935d1e8241afa042c1e29287d2c95c3ed151"}, - {file = "langsmith-0.0.25.tar.gz", hash = "sha256:e728c398fc1adaa0ed8abeb21f6a92d7fb19fe3ab49d3911c22b03dfe25935d6"}, -] - -[package.dependencies] -pydantic = ">=1,<3" -requests = ">=2,<3" +all = ["beautifulsoup4 (>=4,<5)", "elasticsearch (>=8,<9)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "jinja2 (>=3,<4)", "manifest-ml (>=0.0.1,<0.0.2)", "nltk (>=3,<4)", "pinecone-client (>=2,<3)", "qdrant-client (>=0.11.7,<0.12.0)", "redis (>=4,<5)", "spacy (>=3,<4)", "tiktoken (>=0,<1)", "torch (>=1,<2)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] +llms = ["manifest-ml (>=0.0.1,<0.0.2)", "torch (>=1,<2)", "transformers (>=4,<5)"] [[package]] -======= -all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.2.6,<0.3.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=3,<4)", "deeplake (>=3.3.0,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=2.8.6,<3.0.0)", "elasticsearch (>=8,<9)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jina (>=3.14,<4.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.1.dev3,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "momento (>=1.5.0,<2.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.1.2,<2.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "spacy (>=3,<4)", "steamship (>=2.16.9,<3.0.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tiktoken (>=0.3.2,<0.4.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] -azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "openai (>=0,<1)"] -cohere = ["cohere (>=3,<4)"] -docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] -embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "chardet (>=5.1.0,<6.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "psychicapi (>=0.5,<0.6)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "telethon (>=1.28.5,<2.0.0)", "tqdm (>=4.48.0)", "zep-python (>=0.30,<0.31)"] -llms = ["anthropic (>=0.2.6,<0.3.0)", "cohere (>=3,<4)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] -openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.4.0)"] -qdrant = ["qdrant-client (>=1.1.2,<2.0.0)"] -text-helpers = ["chardet (>=5.1.0,<6.0.0)"] - -[[package]] ->>>>>>> second-repo/main name = "llama-index" version = "0.5.4" description = "Interface between LLMs and your data." @@ -2594,13 +1732,13 @@ tiktoken = "*" [[package]] name = "loguru" -version = "0.7.0" +version = "0.7.1" description = "Python logging made (stupidly) simple" optional = false python-versions = ">=3.5" files = [ - {file = "loguru-0.7.0-py3-none-any.whl", hash = "sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"}, - {file = "loguru-0.7.0.tar.gz", hash = "sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1"}, + {file = "loguru-0.7.1-py3-none-any.whl", hash = "sha256:046bf970cb3cad77a28d607cbf042ac25a407db987a1e801c7f7e692469982f9"}, + {file = "loguru-0.7.1.tar.gz", hash = "sha256:7ba2a7d81b79a412b0ded69bd921e012335e80fd39937a633570f273a343579e"}, ] [package.dependencies] @@ -2608,20 +1746,15 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v0.990)", "pre-commit (==3.2.1)", "pytest (==6.1.2)", "pytest (==7.2.1)", "pytest-cov (==2.12.1)", "pytest-cov (==4.0.0)", "pytest-mypy-plugins (==1.10.1)", "pytest-mypy-plugins (==1.9.3)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.2.0)", "tox (==3.27.1)", "tox (==4.4.6)"] +dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "pre-commit (==3.3.1)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] [[package]] name = "lxml" -<<<<<<< HEAD version = "4.9.3" -======= -version = "4.9.2" ->>>>>>> second-repo/main description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ -<<<<<<< HEAD {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, @@ -2714,96 +1847,13 @@ files = [ {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, -======= - {file = "lxml-4.9.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a"}, - {file = "lxml-4.9.2-cp27-cp27m-win32.whl", hash = "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de"}, - {file = "lxml-4.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975"}, - {file = "lxml-4.9.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184"}, - {file = "lxml-4.9.2-cp310-cp310-win32.whl", hash = "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda"}, - {file = "lxml-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1"}, - {file = "lxml-4.9.2-cp311-cp311-win32.whl", hash = "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33"}, - {file = "lxml-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e"}, - {file = "lxml-4.9.2-cp35-cp35m-win32.whl", hash = "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df"}, - {file = "lxml-4.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5"}, - {file = "lxml-4.9.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38"}, - {file = "lxml-4.9.2-cp36-cp36m-win32.whl", hash = "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5"}, - {file = "lxml-4.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3"}, - {file = "lxml-4.9.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b"}, - {file = "lxml-4.9.2-cp37-cp37m-win32.whl", hash = "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe"}, - {file = "lxml-4.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9"}, - {file = "lxml-4.9.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457"}, - {file = "lxml-4.9.2-cp38-cp38-win32.whl", hash = "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b"}, - {file = "lxml-4.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7"}, - {file = "lxml-4.9.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2"}, - {file = "lxml-4.9.2-cp39-cp39-win32.whl", hash = "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1"}, - {file = "lxml-4.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409"}, - {file = "lxml-4.9.2.tar.gz", hash = "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67"}, ->>>>>>> second-repo/main ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -<<<<<<< HEAD source = ["Cython (>=0.29.35)"] -======= -source = ["Cython (>=0.29.7)"] ->>>>>>> second-repo/main [[package]] name = "lz4" @@ -2856,7 +1906,6 @@ tests = ["psutil", "pytest (!=3.3.0)", "pytest-cov"] [[package]] name = "marshmallow" -<<<<<<< HEAD version = "3.20.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false @@ -2864,46 +1913,17 @@ python-versions = ">=3.8" files = [ {file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"}, {file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889"}, -======= -version = "3.19.0" -description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -optional = false -python-versions = ">=3.7" -files = [ - {file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"}, - {file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"}, ->>>>>>> second-repo/main ] [package.dependencies] packaging = ">=17.0" [package.extras] -<<<<<<< HEAD dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] -======= -dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"] ->>>>>>> second-repo/main tests = ["pytest", "pytz", "simplejson"] -[[package]] -name = "marshmallow-enum" -version = "1.5.1" -description = "Enum field for Marshmallow" -optional = false -python-versions = "*" -files = [ - {file = "marshmallow-enum-1.5.1.tar.gz", hash = "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58"}, - {file = "marshmallow_enum-1.5.1-py2.py3-none-any.whl", hash = "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"}, -] - -[package.dependencies] -marshmallow = ">=2.0.0" - [[package]] name = "monotonic" version = "1.6" @@ -2917,7 +1937,6 @@ files = [ [[package]] name = "more-itertools" -<<<<<<< HEAD version = "10.1.0" description = "More routines for operating on iterables, beyond itertools" optional = false @@ -2925,15 +1944,6 @@ python-versions = ">=3.8" files = [ {file = "more-itertools-10.1.0.tar.gz", hash = "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a"}, {file = "more_itertools-10.1.0-py3-none-any.whl", hash = "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6"}, -======= -version = "9.1.0" -description = "More routines for operating on iterables, beyond itertools" -optional = false -python-versions = ">=3.7" -files = [ - {file = "more-itertools-9.1.0.tar.gz", hash = "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d"}, - {file = "more_itertools-9.1.0-py3-none-any.whl", hash = "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"}, ->>>>>>> second-repo/main ] [[package]] @@ -2955,30 +1965,17 @@ tests = ["pytest (>=4.6)"] [[package]] name = "msal" -<<<<<<< HEAD version = "1.23.0" -======= -version = "1.22.0" ->>>>>>> second-repo/main description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = "*" files = [ -<<<<<<< HEAD {file = "msal-1.23.0-py2.py3-none-any.whl", hash = "sha256:3342e0837a047007f9d479e814b559c3219767453d57920dc40a31986862048b"}, {file = "msal-1.23.0.tar.gz", hash = "sha256:25c9a33acf84301f93d1fdbe9f1a9c60cd38af0d5fffdbfa378138fc7bc1e86b"}, ] [package.dependencies] cryptography = ">=0.6,<44" -======= - {file = "msal-1.22.0-py2.py3-none-any.whl", hash = "sha256:9120b7eafdf061c92f7b3d744e5f325fca35873445fa8ffebb40b1086a13dd58"}, - {file = "msal-1.22.0.tar.gz", hash = "sha256:8a82f5375642c1625c89058018430294c109440dce42ea667d466c2cab520acd"}, -] - -[package.dependencies] -cryptography = ">=0.6,<43" ->>>>>>> second-repo/main PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" @@ -3097,88 +2094,8 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -[[package]] -name = "numexpr" -<<<<<<< HEAD -version = "2.8.5" -======= -version = "2.8.4" ->>>>>>> second-repo/main -description = "Fast numerical expression evaluator for NumPy" -optional = false -python-versions = ">=3.7" -files = [ -<<<<<<< HEAD - {file = "numexpr-2.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51f3ab160c3847ebcca93cd88f935a7802b54a01ab63fe93152994a64d7a6cf2"}, - {file = "numexpr-2.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:de29c77f674e4eb8f0846525a475cab64008c227c8bc4ba5153ab3f72441cc63"}, - {file = "numexpr-2.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf85ba1327eb87ec82ae7936f13c8850fb969a0ca34f3ba9fa3897c09d5c80d7"}, - {file = "numexpr-2.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c00be69f747f44a631830215cab482f0f77f75af2925695adff57c1cc0f9a68"}, - {file = "numexpr-2.8.5-cp310-cp310-win32.whl", hash = "sha256:c46350dcdb93e32f033eea5a21269514ffcaf501d9abd6036992d37e48a308b0"}, - {file = "numexpr-2.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:894b027438b8ec88dea32a19193716c79f4ff8ddb92302dcc9731b51ba3565a8"}, - {file = "numexpr-2.8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6df184d40d4cf9f21c71f429962f39332f7398147762588c9f3a5c77065d0c06"}, - {file = "numexpr-2.8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:178b85ad373c6903e55d75787d61b92380439b70d94b001cb055a501b0821335"}, - {file = "numexpr-2.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:578fe4008e4d5d6ff01bbeb2d7b7ba1ec658a5cda9c720cd26a9a8325f8ef438"}, - {file = "numexpr-2.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef621b4ee366a5c6a484f6678c9259f5b826569f8bfa0b89ba2306d5055468bb"}, - {file = "numexpr-2.8.5-cp311-cp311-win32.whl", hash = "sha256:dd57ab1a3d3aaa9274aff1cefbf93b8ddacc7973afef5b125905f6bf18fabab0"}, - {file = "numexpr-2.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:783324ba40eb804ecfc9ebae86120a1e339ab112d0ab8a1f0d48a26354d5bf9b"}, - {file = "numexpr-2.8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:183d5430db76826e54465c69db93a3c6ecbf03cda5aa1bb96eaad0147e9b68dc"}, - {file = "numexpr-2.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ce106f92ccea5b07b1d6f2f3c4370f05edf27691dc720a63903484a2137e48"}, - {file = "numexpr-2.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b594dc9e2d6291a0bc5c065e6d9caf3eee743b5663897832e9b17753c002947a"}, - {file = "numexpr-2.8.5-cp37-cp37m-win32.whl", hash = "sha256:62b4faf8e0627673b0210a837792bddd23050ecebc98069ab23eb0633ff1ef5f"}, - {file = "numexpr-2.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:db5c65417d69414f1ab31302ea01d3548303ef31209c38b4849d145be4e1d1ba"}, - {file = "numexpr-2.8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb36ffcfa1606e41aa08d559b4277bcad0e16b83941d1a4fee8d2bd5a34f8e0e"}, - {file = "numexpr-2.8.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:34af2a0e857d02a4bc5758bc037a777d50dacb13bcd57c7905268a3e44994ed6"}, - {file = "numexpr-2.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a8dad2bfaad5a5c34a2e8bbf62b9df1dfab266d345fda1feb20ff4e264b347a"}, - {file = "numexpr-2.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93f5a866cd13a808bc3d3a9c487d94cd02eec408b275ff0aa150f2e8e5191f8"}, - {file = "numexpr-2.8.5-cp38-cp38-win32.whl", hash = "sha256:558390fea6370003ac749ed9d0f38d708aa096f5dcb707ddb6e0ca5a0dd37da1"}, - {file = "numexpr-2.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:55983806815035eb63c5039520688c49536bb7f3cc3fc1d7d64c6a00cf3f353e"}, - {file = "numexpr-2.8.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1510da20e6f5f45333610b1ded44c566e2690c6c437c84f2a212ca09627c7e01"}, - {file = "numexpr-2.8.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e8b5bf7bcb4e8dcd66522d8fc96e1db7278f901cb4fd2e155efbe62a41dde08"}, - {file = "numexpr-2.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ed0e1c1ef5f34381448539f1fe9015906d21c9cfa2797c06194d4207dadb465"}, - {file = "numexpr-2.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aea6ab45c87c0a7041183c08a798f0ad4d7c5eccbce20cfe79ce6f1a45ef3702"}, - {file = "numexpr-2.8.5-cp39-cp39-win32.whl", hash = "sha256:cbfd833ee5fdb0efb862e152aee7e6ccea9c596d5c11d22604c2e6307bff7cad"}, - {file = "numexpr-2.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:283ce8609a7ccbadf91a68f3484558b3e36d27c93c98a41ec205efb0ab43c872"}, - {file = "numexpr-2.8.5.tar.gz", hash = "sha256:45ed41e55a0abcecf3d711481e12a5fb7a904fe99d42bc282a17cc5f8ea510be"}, -======= - {file = "numexpr-2.8.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a75967d46b6bd56455dd32da6285e5ffabe155d0ee61eef685bbfb8dafb2e484"}, - {file = "numexpr-2.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db93cf1842f068247de631bfc8af20118bf1f9447cd929b531595a5e0efc9346"}, - {file = "numexpr-2.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bca95f4473b444428061d4cda8e59ac564dc7dc6a1dea3015af9805c6bc2946"}, - {file = "numexpr-2.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e34931089a6bafc77aaae21f37ad6594b98aa1085bb8b45d5b3cd038c3c17d9"}, - {file = "numexpr-2.8.4-cp310-cp310-win32.whl", hash = "sha256:f3a920bfac2645017110b87ddbe364c9c7a742870a4d2f6120b8786c25dc6db3"}, - {file = "numexpr-2.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:6931b1e9d4f629f43c14b21d44f3f77997298bea43790cfcdb4dd98804f90783"}, - {file = "numexpr-2.8.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9400781553541f414f82eac056f2b4c965373650df9694286b9bd7e8d413f8d8"}, - {file = "numexpr-2.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ee9db7598dd4001138b482342b96d78110dd77cefc051ec75af3295604dde6a"}, - {file = "numexpr-2.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff5835e8af9a212e8480003d731aad1727aaea909926fd009e8ae6a1cba7f141"}, - {file = "numexpr-2.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:655d84eb09adfee3c09ecf4a89a512225da153fdb7de13c447404b7d0523a9a7"}, - {file = "numexpr-2.8.4-cp311-cp311-win32.whl", hash = "sha256:5538b30199bfc68886d2be18fcef3abd11d9271767a7a69ff3688defe782800a"}, - {file = "numexpr-2.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:3f039321d1c17962c33079987b675fb251b273dbec0f51aac0934e932446ccc3"}, - {file = "numexpr-2.8.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c867cc36cf815a3ec9122029874e00d8fbcef65035c4a5901e9b120dd5d626a2"}, - {file = "numexpr-2.8.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:059546e8f6283ccdb47c683101a890844f667fa6d56258d48ae2ecf1b3875957"}, - {file = "numexpr-2.8.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:845a6aa0ed3e2a53239b89c1ebfa8cf052d3cc6e053c72805e8153300078c0b1"}, - {file = "numexpr-2.8.4-cp37-cp37m-win32.whl", hash = "sha256:a38664e699526cb1687aefd9069e2b5b9387da7feac4545de446141f1ef86f46"}, - {file = "numexpr-2.8.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eaec59e9bf70ff05615c34a8b8d6c7bd042bd9f55465d7b495ea5436f45319d0"}, - {file = "numexpr-2.8.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b318541bf3d8326682ebada087ba0050549a16d8b3fa260dd2585d73a83d20a7"}, - {file = "numexpr-2.8.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b076db98ca65eeaf9bd224576e3ac84c05e451c0bd85b13664b7e5f7b62e2c70"}, - {file = "numexpr-2.8.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90f12cc851240f7911a47c91aaf223dba753e98e46dff3017282e633602e76a7"}, - {file = "numexpr-2.8.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c368aa35ae9b18840e78b05f929d3a7b3abccdba9630a878c7db74ca2368339"}, - {file = "numexpr-2.8.4-cp38-cp38-win32.whl", hash = "sha256:b96334fc1748e9ec4f93d5fadb1044089d73fb08208fdb8382ed77c893f0be01"}, - {file = "numexpr-2.8.4-cp38-cp38-win_amd64.whl", hash = "sha256:a6d2d7740ae83ba5f3531e83afc4b626daa71df1ef903970947903345c37bd03"}, - {file = "numexpr-2.8.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:77898fdf3da6bb96aa8a4759a8231d763a75d848b2f2e5c5279dad0b243c8dfe"}, - {file = "numexpr-2.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df35324666b693f13a016bc7957de7cc4d8801b746b81060b671bf78a52b9037"}, - {file = "numexpr-2.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ac9cfe6d0078c5fc06ba1c1bbd20b8783f28c6f475bbabd3cad53683075cab"}, - {file = "numexpr-2.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df3a1f6b24214a1ab826e9c1c99edf1686c8e307547a9aef33910d586f626d01"}, - {file = "numexpr-2.8.4-cp39-cp39-win32.whl", hash = "sha256:7d71add384adc9119568d7e9ffa8a35b195decae81e0abf54a2b7779852f0637"}, - {file = "numexpr-2.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:9f096d707290a6a00b6ffdaf581ee37331109fb7b6c8744e9ded7c779a48e517"}, - {file = "numexpr-2.8.4.tar.gz", hash = "sha256:d5432537418d18691b9115d615d6daa17ee8275baef3edf1afbbf8bc69806147"}, ->>>>>>> second-repo/main -] - -[package.dependencies] -numpy = ">=1.13.3" - [[package]] name = "numpy" -<<<<<<< HEAD version = "1.25.2" description = "Fundamental package for array computing in Python" optional = false @@ -3209,55 +2126,15 @@ files = [ {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, -======= -version = "1.24.3" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"}, - {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"}, - {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"}, - {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"}, - {file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"}, - {file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"}, - {file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"}, - {file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"}, - {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"}, - {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"}, - {file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"}, - {file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"}, - {file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"}, - {file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"}, - {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"}, - {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"}, - {file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"}, - {file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"}, - {file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"}, - {file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"}, - {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"}, - {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"}, - {file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"}, - {file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"}, - {file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"}, - {file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"}, - {file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"}, - {file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"}, ->>>>>>> second-repo/main ] [[package]] name = "onnxruntime" -<<<<<<< HEAD version = "1.15.1" -======= -version = "1.15.0" ->>>>>>> second-repo/main description = "ONNX Runtime is a runtime accelerator for Machine Learning models" optional = false python-versions = "*" files = [ -<<<<<<< HEAD {file = "onnxruntime-1.15.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:baad59e6a763237fa39545325d29c16f98b8a45d2dfc524c67631e2e3ba44d16"}, {file = "onnxruntime-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:568c2db848f619a0a93e843c028e9fb4879929d40b04bd60f9ba6eb8d2e93421"}, {file = "onnxruntime-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69088d7784bb04dedfd9e883e2c96e4adf8ae0451acdd0abb78d68f59ecc6d9d"}, @@ -3282,32 +2159,6 @@ files = [ {file = "onnxruntime-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:985693d18f2d46aa34fd44d7f65ff620660b2c8fa4b8ec365c2ca353f0fbdb27"}, {file = "onnxruntime-1.15.1-cp39-cp39-win32.whl", hash = "sha256:708eb31b0c04724bf0f01c1309a9e69bbc09b85beb750e5662c8aed29f1ff9fd"}, {file = "onnxruntime-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:73d6de4c42dfde1e9dbea04773e6dc23346c8cda9c7e08c6554fafc97ac60138"}, -======= - {file = "onnxruntime-1.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a61c6ff118e01d0800b19cbed8aa64cf687edd60e6d0cc39f0e9900ad324c212"}, - {file = "onnxruntime-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:413495938e389f087c1dbc61168fbb4c5460610c0bac542c7ec3bcfba64b6bfd"}, - {file = "onnxruntime-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbcd117186826a7b81afa10a2a4bb3882302149b07351ab5add367daf8e245cf"}, - {file = "onnxruntime-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34caf6e11b12d199c4029b6717fc679d12b41ef05a8d34badff3977eb459d5ac"}, - {file = "onnxruntime-1.15.0-cp310-cp310-win32.whl", hash = "sha256:3155fcfa546db5d31859235a4ab21c70d10a933a3df8354a1269d3a6def1b743"}, - {file = "onnxruntime-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:1ffde3e22d2969aeb9ab8fea3adfd7a568d28e6a2f05c369e562056a52510857"}, - {file = "onnxruntime-1.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:3c89bceb1dd172ab8b288fca48eb0ac3d68796041abcd49537108581a14748ad"}, - {file = "onnxruntime-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3216524f10b805831ac606718966c5623f001762c1fb70aa107691e03b20e8ae"}, - {file = "onnxruntime-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99c34478cf34d64d72ed5fb0642c9e19d1bc1a42be9ffeda31420dc23a4d0af2"}, - {file = "onnxruntime-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ff833c740a5054e9eba734eb1c13d6925d5a84adf1102179e46b20effe5e1a6"}, - {file = "onnxruntime-1.15.0-cp311-cp311-win32.whl", hash = "sha256:cd3bbdb6cff207a3696c5a370717280bc04f0824de27dc03b51292b23fcff0ad"}, - {file = "onnxruntime-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:335f26b663295f50921437f74620bc0ee8b25707a1a8987a8142452d5283d098"}, - {file = "onnxruntime-1.15.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:563c56bbf7331686cb72d93b47fa96f4fdf883dbdf7398dc07ba6011a4311c40"}, - {file = "onnxruntime-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:de66cd57e8db8be3783ce478eaade75c07e9b1ce0f3c12500b34d1683d6c13e5"}, - {file = "onnxruntime-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:101310d7ed44b43f35d1158033266b9df4994b80691ded7517f389d7fc281353"}, - {file = "onnxruntime-1.15.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df38690e495c57ae3d160210c3567a53f0b38dcc4526983af69e89a6f762d9"}, - {file = "onnxruntime-1.15.0-cp38-cp38-win32.whl", hash = "sha256:84ad51d1be998a250acd93e61f1db699628b523caf12c3bf863c3204e9e6ceda"}, - {file = "onnxruntime-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:4d443c544370e28d2ad2d5e472ba32eb7cbc62ef7e315e66ec75c3292f47cee5"}, - {file = "onnxruntime-1.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:80861aa47817fa0db29f5e818e567afd2b0013373418413435cc3dd361458fe8"}, - {file = "onnxruntime-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df402e46432fb038fca9bfe8d1a489396b54b6253ec26398f6d8b0322276fc99"}, - {file = "onnxruntime-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c5afc01e0109f26a06ea19e132f7b934878ec81fac4557d35c5f3d01ca2a17"}, - {file = "onnxruntime-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67bbb583d7f6f98c831945f664a5d302a65c3cc9dc8da793d2acce0260650927"}, - {file = "onnxruntime-1.15.0-cp39-cp39-win32.whl", hash = "sha256:b21438216c0a9985c224938431259959ddf71c7949f9e5759d6ad68fb5f61717"}, - {file = "onnxruntime-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:e83521ddbeef421c3e697a7cc803e826a0d1b7a40446a857572700b6ab5f4083"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -3320,22 +2171,13 @@ sympy = "*" [[package]] name = "openai" -<<<<<<< HEAD -version = "0.27.8" -======= -version = "0.27.7" ->>>>>>> second-repo/main +version = "0.27.10" description = "Python client library for the OpenAI API" optional = false python-versions = ">=3.7.1" files = [ -<<<<<<< HEAD - {file = "openai-0.27.8-py3-none-any.whl", hash = "sha256:e0a7c2f7da26bdbe5354b03c6d4b82a2f34bd4458c7a17ae1a7092c3e397e03c"}, - {file = "openai-0.27.8.tar.gz", hash = "sha256:2483095c7db1eee274cebac79e315a986c4e55207bb4fa7b82d185b3a2ed9536"}, -======= - {file = "openai-0.27.7-py3-none-any.whl", hash = "sha256:788fb7fa85bf7caac6c1ed7eea5984254a1bdaf09ef485acf0e5718c8b2dc25a"}, - {file = "openai-0.27.7.tar.gz", hash = "sha256:bca95fd4c3054ef38924def096396122130454442ec52005915ecf8269626b1d"}, ->>>>>>> second-repo/main + {file = "openai-0.27.10-py3-none-any.whl", hash = "sha256:beabd1757e3286fa166dde3b70ebb5ad8081af046876b47c14c41e203ed22a14"}, + {file = "openai-0.27.10.tar.gz", hash = "sha256:60e09edf7100080283688748c6803b7b3b52d5a55d21890f3815292a0552d83b"}, ] [package.dependencies] @@ -3350,38 +2192,14 @@ embeddings = ["matplotlib", "numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", " wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "wandb"] [[package]] -<<<<<<< HEAD name = "overrides" version = "7.4.0" -======= -name = "openapi-schema-pydantic" -version = "1.2.4" -description = "OpenAPI (v3) specification schema as pydantic class" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "openapi-schema-pydantic-1.2.4.tar.gz", hash = "sha256:3e22cf58b74a69f752cc7e5f1537f6e44164282db2700cbbcd3bb99ddd065196"}, - {file = "openapi_schema_pydantic-1.2.4-py3-none-any.whl", hash = "sha256:a932ecc5dcbb308950282088956e94dea069c9823c84e507d64f6b622222098c"}, -] - -[package.dependencies] -pydantic = ">=1.8.2" - -[[package]] -name = "overrides" -version = "7.3.1" ->>>>>>> second-repo/main description = "A decorator to automatically detect mismatch when overriding a method." optional = false python-versions = ">=3.6" files = [ -<<<<<<< HEAD {file = "overrides-7.4.0-py3-none-any.whl", hash = "sha256:3ad24583f86d6d7a49049695efe9933e67ba62f0c7625d53c59fa832ce4b8b7d"}, {file = "overrides-7.4.0.tar.gz", hash = "sha256:9502a3cca51f4fac40b5feca985b6703a5c1f6ad815588a7ca9e285b9dca6757"}, -======= - {file = "overrides-7.3.1-py3-none-any.whl", hash = "sha256:6187d8710a935d09b0bcef8238301d6ee2569d2ac1ae0ec39a8c7924e27f58ca"}, - {file = "overrides-7.3.1.tar.gz", hash = "sha256:8b97c6c1e1681b78cbc9424b138d880f0803c2254c5ebaabdde57bb6c62093f2"}, ->>>>>>> second-repo/main ] [[package]] @@ -3397,16 +2215,11 @@ files = [ [[package]] name = "pandas" -<<<<<<< HEAD version = "1.5.3" -======= -version = "2.0.2" ->>>>>>> second-repo/main description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.8" files = [ -<<<<<<< HEAD {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, @@ -3434,77 +2247,18 @@ files = [ {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, -======= - {file = "pandas-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ebb9f1c22ddb828e7fd017ea265a59d80461d5a79154b49a4207bd17514d122"}, - {file = "pandas-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1eb09a242184092f424b2edd06eb2b99d06dc07eeddff9929e8667d4ed44e181"}, - {file = "pandas-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7319b6e68de14e6209460f72a8d1ef13c09fb3d3ef6c37c1e65b35d50b5c145"}, - {file = "pandas-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd46bde7309088481b1cf9c58e3f0e204b9ff9e3244f441accd220dd3365ce7c"}, - {file = "pandas-2.0.2-cp310-cp310-win32.whl", hash = "sha256:51a93d422fbb1bd04b67639ba4b5368dffc26923f3ea32a275d2cc450f1d1c86"}, - {file = "pandas-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:66d00300f188fa5de73f92d5725ced162488f6dc6ad4cecfe4144ca29debe3b8"}, - {file = "pandas-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02755de164da6827764ceb3bbc5f64b35cb12394b1024fdf88704d0fa06e0e2f"}, - {file = "pandas-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0a1e0576611641acde15c2322228d138258f236d14b749ad9af498ab69089e2d"}, - {file = "pandas-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6b5f14cd24a2ed06e14255ff40fe2ea0cfaef79a8dd68069b7ace74bd6acbba"}, - {file = "pandas-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50e451932b3011b61d2961b4185382c92cc8c6ee4658dcd4f320687bb2d000ee"}, - {file = "pandas-2.0.2-cp311-cp311-win32.whl", hash = "sha256:7b21cb72958fc49ad757685db1919021d99650d7aaba676576c9e88d3889d456"}, - {file = "pandas-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:c4af689352c4fe3d75b2834933ee9d0ccdbf5d7a8a7264f0ce9524e877820c08"}, - {file = "pandas-2.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:69167693cb8f9b3fc060956a5d0a0a8dbfed5f980d9fd2c306fb5b9c855c814c"}, - {file = "pandas-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:30a89d0fec4263ccbf96f68592fd668939481854d2ff9da709d32a047689393b"}, - {file = "pandas-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a18e5c72b989ff0f7197707ceddc99828320d0ca22ab50dd1b9e37db45b010c0"}, - {file = "pandas-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7376e13d28eb16752c398ca1d36ccfe52bf7e887067af9a0474de6331dd948d2"}, - {file = "pandas-2.0.2-cp38-cp38-win32.whl", hash = "sha256:6d6d10c2142d11d40d6e6c0a190b1f89f525bcf85564707e31b0a39e3b398e08"}, - {file = "pandas-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:e69140bc2d29a8556f55445c15f5794490852af3de0f609a24003ef174528b79"}, - {file = "pandas-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b42b120458636a981077cfcfa8568c031b3e8709701315e2bfa866324a83efa8"}, - {file = "pandas-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f908a77cbeef9bbd646bd4b81214cbef9ac3dda4181d5092a4aa9797d1bc7774"}, - {file = "pandas-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713f2f70abcdade1ddd68fc91577cb090b3544b07ceba78a12f799355a13ee44"}, - {file = "pandas-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf3f0c361a4270185baa89ec7ab92ecaa355fe783791457077473f974f654df5"}, - {file = "pandas-2.0.2-cp39-cp39-win32.whl", hash = "sha256:598e9020d85a8cdbaa1815eb325a91cfff2bb2b23c1442549b8a3668e36f0f77"}, - {file = "pandas-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:77550c8909ebc23e56a89f91b40ad01b50c42cfbfab49b3393694a50549295ea"}, - {file = "pandas-2.0.2.tar.gz", hash = "sha256:dd5476b6c3fe410ee95926873f377b856dbc4e81a9c605a0dc05aaccc6a7c6c6"}, ->>>>>>> second-repo/main ] [package.dependencies] numpy = [ -<<<<<<< HEAD + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.1" pytz = ">=2020.1" [package.extras] test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] -======= - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, -] -python-dateutil = ">=2.8.2" -pytz = ">=2020.1" -tzdata = ">=2022.1" - -[package.extras] -all = ["PyQt5 (>=5.15.1)", "SQLAlchemy (>=1.4.16)", "beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.2)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "s3fs (>=2021.08.0)", "scipy (>=1.7.1)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] -aws = ["s3fs (>=2021.08.0)"] -clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] -compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] -computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] -feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2021.07.0)"] -gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] -hdf5 = ["tables (>=3.6.1)"] -html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] -mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] -parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] -plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] -spss = ["pyreadstat (>=1.1.2)"] -sql-other = ["SQLAlchemy (>=1.4.16)"] -test = ["hypothesis (>=6.34.2)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.6.3)"] ->>>>>>> second-repo/main [[package]] name = "pgvector" @@ -3521,69 +2275,6 @@ numpy = "*" [[package]] name = "pillow" -<<<<<<< HEAD -version = "10.0.0" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, - {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, - {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, - {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, - {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, - {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, - {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, - {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, - {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, - {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, - {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, - {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, - {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, - {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, - {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, - {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, - {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, - {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, - {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, - {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, - {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, - {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, - {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, - {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, - {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, - {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, - {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, - {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, -======= version = "9.5.0" description = "Python Imaging Library (Fork)" optional = false @@ -3655,7 +2346,6 @@ files = [ {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"}, {file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"}, {file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"}, ->>>>>>> second-repo/main ] [package.extras] @@ -3664,7 +2354,6 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "pinecone-client" -<<<<<<< HEAD version = "2.2.2" description = "Pinecone client and SDK" optional = false @@ -3672,25 +2361,12 @@ python-versions = ">=3.8" files = [ {file = "pinecone-client-2.2.2.tar.gz", hash = "sha256:391fe413754efd4e0ef00154b44271d63c4cdd4bedf088d23111a5725d863210"}, {file = "pinecone_client-2.2.2-py3-none-any.whl", hash = "sha256:21fddb752668efee4d3c6b706346d9580e36a8b06b8d97afd60bd33ef2536e7e"}, -======= -version = "2.2.1" -description = "Pinecone client and SDK" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pinecone-client-2.2.1.tar.gz", hash = "sha256:0878dcaee447c46c8d1b3d71c854689daa7e548e5009a171780907c7d4e74789"}, - {file = "pinecone_client-2.2.1-py3-none-any.whl", hash = "sha256:6976a22aee57a9813378607506c8c36b0317dfa36a08a5397aaaeab2eef66c1b"}, ->>>>>>> second-repo/main ] [package.dependencies] dnspython = ">=2.0.0" loguru = ">=0.5.0" -<<<<<<< HEAD numpy = ">=1.22.0" -======= -numpy = "*" ->>>>>>> second-repo/main python-dateutil = ">=2.5.3" pyyaml = ">=5.4" requests = ">=2.19.0" @@ -3699,11 +2375,7 @@ typing-extensions = ">=3.7.4" urllib3 = ">=1.21.1" [package.extras] -<<<<<<< HEAD grpc = ["googleapis-common-protos (>=1.53.0)", "grpc-gateway-protoc-gen-openapiv2 (==0.1.0)", "grpcio (>=1.44.0)", "lz4 (>=3.1.3)", "protobuf (>=3.19.5,<3.20.0)"] -======= -grpc = ["googleapis-common-protos (>=1.53.0)", "grpc-gateway-protoc-gen-openapiv2 (==0.1.0)", "grpcio (>=1.44.0)", "lz4 (>=3.1.3)", "protobuf (==3.19.3)"] ->>>>>>> second-repo/main [[package]] name = "pkginfo" @@ -3721,23 +2393,13 @@ testing = ["pytest", "pytest-cov"] [[package]] name = "pluggy" -<<<<<<< HEAD -version = "1.2.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, -======= -version = "1.0.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ->>>>>>> second-repo/main + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] [package.extras] @@ -3782,22 +2444,13 @@ strenum = ">=0.4.9,<0.5.0" [[package]] name = "posthog" -<<<<<<< HEAD version = "3.0.2" -======= -version = "3.0.1" ->>>>>>> second-repo/main description = "Integrate PostHog into any python application." optional = false python-versions = "*" files = [ -<<<<<<< HEAD {file = "posthog-3.0.2-py2.py3-none-any.whl", hash = "sha256:a8c0af6f2401fbe50f90e68c4143d0824b54e872de036b1c2f23b5abb39d88ce"}, {file = "posthog-3.0.2.tar.gz", hash = "sha256:701fba6e446a4de687c6e861b587e7b7741955ad624bf34fe013c06a0fec6fb3"}, -======= - {file = "posthog-3.0.1-py2.py3-none-any.whl", hash = "sha256:9c7f92fecc713257d4b2710d05b456569c9156fbdd3e85655ba7ba5ba6c7b3ae"}, - {file = "posthog-3.0.1.tar.gz", hash = "sha256:57d2791ff5752ce56ba0f9bb8876faf3ca9208f1c2c6ceaeb5a2504c34493767"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -3814,58 +2467,33 @@ test = ["coverage", "flake8", "freezegun (==0.3.15)", "mock (>=2.0.0)", "pylint" [[package]] name = "protobuf" -<<<<<<< HEAD -version = "4.24.1" -======= -version = "4.23.2" ->>>>>>> second-repo/main +version = "4.24.2" description = "" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD - {file = "protobuf-4.24.1-cp310-abi3-win32.whl", hash = "sha256:d414199ca605eeb498adc4d2ba82aedc0379dca4a7c364ff9bc9a179aa28e71b"}, - {file = "protobuf-4.24.1-cp310-abi3-win_amd64.whl", hash = "sha256:5906c5e79ff50fe38b2d49d37db5874e3c8010826f2362f79996d83128a8ed9b"}, - {file = "protobuf-4.24.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:970c701ee16788d74f3de20938520d7a0aebc7e4fff37096a48804c80d2908cf"}, - {file = "protobuf-4.24.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fc361148e902949dcb953bbcb148c99fe8f8854291ad01107e4120361849fd0e"}, - {file = "protobuf-4.24.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:5d32363d14aca6e5c9e9d5918ad8fb65b091b6df66740ae9de50ac3916055e43"}, - {file = "protobuf-4.24.1-cp37-cp37m-win32.whl", hash = "sha256:df015c47d6855b8efa0b9be706c70bf7f050a4d5ac6d37fb043fbd95157a0e25"}, - {file = "protobuf-4.24.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d4af4fd9e9418e819be30f8df2a16e72fbad546a7576ac7f3653be92a6966d30"}, - {file = "protobuf-4.24.1-cp38-cp38-win32.whl", hash = "sha256:302e8752c760549ed4c7a508abc86b25d46553c81989343782809e1a062a2ef9"}, - {file = "protobuf-4.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:06437f0d4bb0d5f29e3d392aba69600188d4be5ad1e0a3370e581a9bf75a3081"}, - {file = "protobuf-4.24.1-cp39-cp39-win32.whl", hash = "sha256:0b2b224e9541fe9f046dd7317d05f08769c332b7e4c54d93c7f0f372dedb0b1a"}, - {file = "protobuf-4.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd39b9094a4cc003a1f911b847ab379f89059f478c0b611ba1215053e295132e"}, - {file = "protobuf-4.24.1-py3-none-any.whl", hash = "sha256:55dd644adc27d2a624339332755fe077c7f26971045b469ebb9732a69ce1f2ca"}, - {file = "protobuf-4.24.1.tar.gz", hash = "sha256:44837a5ed9c9418ad5d502f89f28ba102e9cd172b6668bc813f21716f9273348"}, -======= - {file = "protobuf-4.23.2-cp310-abi3-win32.whl", hash = "sha256:384dd44cb4c43f2ccddd3645389a23ae61aeb8cfa15ca3a0f60e7c3ea09b28b3"}, - {file = "protobuf-4.23.2-cp310-abi3-win_amd64.whl", hash = "sha256:09310bce43353b46d73ba7e3bca78273b9bc50349509b9698e64d288c6372c2a"}, - {file = "protobuf-4.23.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2cfab63a230b39ae603834718db74ac11e52bccaaf19bf20f5cce1a84cf76df"}, - {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:c52cfcbfba8eb791255edd675c1fe6056f723bf832fa67f0442218f8817c076e"}, - {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:86df87016d290143c7ce3be3ad52d055714ebaebb57cc659c387e76cfacd81aa"}, - {file = "protobuf-4.23.2-cp37-cp37m-win32.whl", hash = "sha256:281342ea5eb631c86697e1e048cb7e73b8a4e85f3299a128c116f05f5c668f8f"}, - {file = "protobuf-4.23.2-cp37-cp37m-win_amd64.whl", hash = "sha256:ce744938406de1e64b91410f473736e815f28c3b71201302612a68bf01517fea"}, - {file = "protobuf-4.23.2-cp38-cp38-win32.whl", hash = "sha256:6c081863c379bb1741be8f8193e893511312b1d7329b4a75445d1ea9955be69e"}, - {file = "protobuf-4.23.2-cp38-cp38-win_amd64.whl", hash = "sha256:25e3370eda26469b58b602e29dff069cfaae8eaa0ef4550039cc5ef8dc004511"}, - {file = "protobuf-4.23.2-cp39-cp39-win32.whl", hash = "sha256:efabbbbac1ab519a514579ba9ec52f006c28ae19d97915951f69fa70da2c9e91"}, - {file = "protobuf-4.23.2-cp39-cp39-win_amd64.whl", hash = "sha256:54a533b971288af3b9926e53850c7eb186886c0c84e61daa8444385a4720297f"}, - {file = "protobuf-4.23.2-py3-none-any.whl", hash = "sha256:8da6070310d634c99c0db7df48f10da495cc283fd9e9234877f0cd182d43ab7f"}, - {file = "protobuf-4.23.2.tar.gz", hash = "sha256:20874e7ca4436f683b64ebdbee2129a5a2c301579a67d1a7dda2cdf62fb7f5f7"}, ->>>>>>> second-repo/main + {file = "protobuf-4.24.2-cp310-abi3-win32.whl", hash = "sha256:58e12d2c1aa428ece2281cef09bbaa6938b083bcda606db3da4e02e991a0d924"}, + {file = "protobuf-4.24.2-cp310-abi3-win_amd64.whl", hash = "sha256:77700b55ba41144fc64828e02afb41901b42497b8217b558e4a001f18a85f2e3"}, + {file = "protobuf-4.24.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:237b9a50bd3b7307d0d834c1b0eb1a6cd47d3f4c2da840802cd03ea288ae8880"}, + {file = "protobuf-4.24.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:25ae91d21e3ce8d874211110c2f7edd6384816fb44e06b2867afe35139e1fd1c"}, + {file = "protobuf-4.24.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:c00c3c7eb9ad3833806e21e86dca448f46035242a680f81c3fe068ff65e79c74"}, + {file = "protobuf-4.24.2-cp37-cp37m-win32.whl", hash = "sha256:4e69965e7e54de4db989289a9b971a099e626f6167a9351e9d112221fc691bc1"}, + {file = "protobuf-4.24.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c5cdd486af081bf752225b26809d2d0a85e575b80a84cde5172a05bbb1990099"}, + {file = "protobuf-4.24.2-cp38-cp38-win32.whl", hash = "sha256:6bd26c1fa9038b26c5c044ee77e0ecb18463e957fefbaeb81a3feb419313a54e"}, + {file = "protobuf-4.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb7aa97c252279da65584af0456f802bd4b2de429eb945bbc9b3d61a42a8cd16"}, + {file = "protobuf-4.24.2-cp39-cp39-win32.whl", hash = "sha256:2b23bd6e06445699b12f525f3e92a916f2dcf45ffba441026357dea7fa46f42b"}, + {file = "protobuf-4.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:839952e759fc40b5d46be319a265cf94920174d88de31657d5622b5d8d6be5cd"}, + {file = "protobuf-4.24.2-py3-none-any.whl", hash = "sha256:3b7b170d3491ceed33f723bbf2d5a260f8a4e23843799a3906f16ef736ef251e"}, + {file = "protobuf-4.24.2.tar.gz", hash = "sha256:7fda70797ddec31ddfa3576cbdcc3ddbb6b3078b737a1a87ab9136af0570cd6e"}, ] [[package]] name = "psycopg2" -<<<<<<< HEAD version = "2.9.7" -======= -version = "2.9.6" ->>>>>>> second-repo/main description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false python-versions = ">=3.6" files = [ -<<<<<<< HEAD {file = "psycopg2-2.9.7-cp310-cp310-win32.whl", hash = "sha256:1a6a2d609bce44f78af4556bea0c62a5e7f05c23e5ea9c599e07678995609084"}, {file = "psycopg2-2.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:b22ed9c66da2589a664e0f1ca2465c29b75aaab36fa209d4fb916025fb9119e5"}, {file = "psycopg2-2.9.7-cp311-cp311-win32.whl", hash = "sha256:44d93a0109dfdf22fe399b419bcd7fa589d86895d3931b01fb321d74dadc68f1"}, @@ -3877,21 +2505,6 @@ files = [ {file = "psycopg2-2.9.7-cp39-cp39-win32.whl", hash = "sha256:c7949770cafbd2f12cecc97dea410c514368908a103acf519f2a346134caa4d5"}, {file = "psycopg2-2.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:b6bd7d9d3a7a63faae6edf365f0ed0e9b0a1aaf1da3ca146e6b043fb3eb5d723"}, {file = "psycopg2-2.9.7.tar.gz", hash = "sha256:f00cc35bd7119f1fed17b85bd1007855194dde2cbd8de01ab8ebb17487440ad8"}, -======= - {file = "psycopg2-2.9.6-cp310-cp310-win32.whl", hash = "sha256:f7a7a5ee78ba7dc74265ba69e010ae89dae635eea0e97b055fb641a01a31d2b1"}, - {file = "psycopg2-2.9.6-cp310-cp310-win_amd64.whl", hash = "sha256:f75001a1cbbe523e00b0ef896a5a1ada2da93ccd752b7636db5a99bc57c44494"}, - {file = "psycopg2-2.9.6-cp311-cp311-win32.whl", hash = "sha256:53f4ad0a3988f983e9b49a5d9765d663bbe84f508ed655affdb810af9d0972ad"}, - {file = "psycopg2-2.9.6-cp311-cp311-win_amd64.whl", hash = "sha256:b81fcb9ecfc584f661b71c889edeae70bae30d3ef74fa0ca388ecda50b1222b7"}, - {file = "psycopg2-2.9.6-cp36-cp36m-win32.whl", hash = "sha256:11aca705ec888e4f4cea97289a0bf0f22a067a32614f6ef64fcf7b8bfbc53744"}, - {file = "psycopg2-2.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:36c941a767341d11549c0fbdbb2bf5be2eda4caf87f65dfcd7d146828bd27f39"}, - {file = "psycopg2-2.9.6-cp37-cp37m-win32.whl", hash = "sha256:869776630c04f335d4124f120b7fb377fe44b0a7645ab3c34b4ba42516951889"}, - {file = "psycopg2-2.9.6-cp37-cp37m-win_amd64.whl", hash = "sha256:a8ad4a47f42aa6aec8d061fdae21eaed8d864d4bb0f0cade5ad32ca16fcd6258"}, - {file = "psycopg2-2.9.6-cp38-cp38-win32.whl", hash = "sha256:2362ee4d07ac85ff0ad93e22c693d0f37ff63e28f0615a16b6635a645f4b9214"}, - {file = "psycopg2-2.9.6-cp38-cp38-win_amd64.whl", hash = "sha256:d24ead3716a7d093b90b27b3d73459fe8cd90fd7065cf43b3c40966221d8c394"}, - {file = "psycopg2-2.9.6-cp39-cp39-win32.whl", hash = "sha256:1861a53a6a0fd248e42ea37c957d36950da00266378746588eab4f4b5649e95f"}, - {file = "psycopg2-2.9.6-cp39-cp39-win_amd64.whl", hash = "sha256:ded2faa2e6dfb430af7713d87ab4abbfc764d8d7fb73eafe96a24155f906ebf5"}, - {file = "psycopg2-2.9.6.tar.gz", hash = "sha256:f15158418fd826831b28585e2ab48ed8df2d0d98f502a2b4fe619e7d5ca29011"}, ->>>>>>> second-repo/main ] [[package]] @@ -3909,43 +2522,42 @@ cffi = ">=1.0" six = "*" [[package]] -<<<<<<< HEAD name = "pulsar-client" -version = "3.2.0" +version = "3.3.0" description = "Apache Pulsar Python client library" optional = false python-versions = "*" files = [ - {file = "pulsar_client-3.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:da53bbe1903026ca1253d36a67bde0ae88513497091658aee8c5514c3e567483"}, - {file = "pulsar_client-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec595a71b7a25f1a72a1350efd6680a511b53253c3cac1911ba3d6c4d71fa64c"}, - {file = "pulsar_client-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3557c65463d74ec8d2864752389beb06761ab591dd134a164e0b1303c66719b"}, - {file = "pulsar_client-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d51dc76fec48217489bde95754ad58288c9389361de42f5a27d64e19840d27fb"}, - {file = "pulsar_client-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9ef2baf85311e0fe1b98342fdafbb93a1818a08ef999eaa524234fedf6f3b941"}, - {file = "pulsar_client-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:0928b02beda0c98e77178f4e30e962ddb8ee8c3320e4c7304a78b0796e976523"}, - {file = "pulsar_client-3.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:584f44b03474a69906be711a597a4d516263a55be31e49fc07be503dc8406821"}, - {file = "pulsar_client-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a637b9a3b30860c61e68a7b8ea650e0987d89e82f73b6a3df1ab662a6438fdda"}, - {file = "pulsar_client-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4a187fdc5febcf16f725179dcf2c476f31eeebd8353794d91754a3202dd5072"}, - {file = "pulsar_client-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5ff879f868cf1fd29db99f39fdb22b3ec3e749c648aca28526689756d922d1c5"}, - {file = "pulsar_client-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4a5f85d0cc414f739a5b51d843f213b54b2cd768c3a34f7c27cca410712b1f81"}, - {file = "pulsar_client-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:4fe748283848d829a80c0323558faeebea4c240d69fa58314ac90344f6999d17"}, - {file = "pulsar_client-3.2.0-cp37-cp37m-macosx_10_15_universal2.whl", hash = "sha256:06b91c26def86dbbc35be15257999fd8a2afbadf32983916ea3eef44f4d4cab4"}, - {file = "pulsar_client-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ec897bc8d232e6b118793378fc662a844334b829a28a1b4ad1c5fe8d019135"}, - {file = "pulsar_client-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa37c96c25c1b5aff3bad0fd0194b385ec190b2c67a2f439ac91577f81ae18d3"}, - {file = "pulsar_client-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d49cdd4d1b7fc2e80d100acf14e6fd3898f6e099e403fc56ed22a690245b2fec"}, - {file = "pulsar_client-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0058ca3191fd24528ccf94dba6f12e4093831454a2597166f96900d0717271bf"}, - {file = "pulsar_client-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:cb69b0411008e0b56df51de0aab20aa1c1a12aef3019b9ceba89afbae1f07fe2"}, - {file = "pulsar_client-3.2.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:f7d33e99602352df7a30707eab4e5781654602212fb618928bffb5523f2bcf35"}, - {file = "pulsar_client-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad1ac15a175ca90555c681a4d0134568771c6346b97a172f3ef14006556a50ae"}, - {file = "pulsar_client-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369e08ef1d5cb196dd9271039928800f90b4701a9c9df90bc068b44260d2fb11"}, - {file = "pulsar_client-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a52ba2b6736a2ebeed31b590e75d417dda149e333461655860efa84d898a3eb4"}, - {file = "pulsar_client-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c801334b3b569b23976481a2922bcea0c6dd990fc26544658dd9e9c8f78ca36"}, - {file = "pulsar_client-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:cd01fd419280e9013d1655bc53662248be2656b623b1506480e1a985aa7dadd2"}, - {file = "pulsar_client-3.2.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:0abe54d84db76435a6cd88ce27610352cabc7efae9fa3e7f874e032ec2ca0b3f"}, - {file = "pulsar_client-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a1b6a806eb4819d8cbab1c4ae44ebf2110a94204a46c365f5757e1455252f2"}, - {file = "pulsar_client-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34ea2a6b75ae0e303d522e5b57c75a4ff03dc18b9bfc14151fb14dfaf5866f17"}, - {file = "pulsar_client-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be6d3a9b2e1db3b6d1a7db5e13f7b4ed420674cf072cdb520fb004c4cd54c0af"}, - {file = "pulsar_client-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6b733e6239ffb505f7084df0175baf9d0215f14d0a02e9bbd1fdf71a2d6ea17"}, - {file = "pulsar_client-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:edc2135d02b4793efb086edca0ffaa6e8ac9133961c2cdc17ae487e0a53da481"}, + {file = "pulsar_client-3.3.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:c31afd3e67a044ff93177df89e08febf214cc965e95ede097d9fe8755af00e01"}, + {file = "pulsar_client-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f66982284571674b215324cc26b5c2f7c56c7043113c47a7084cb70d67a8afb"}, + {file = "pulsar_client-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fe50a06f81c48a75a9b95c27a6446260039adca71d9face273740de96b2efca"}, + {file = "pulsar_client-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d4c46a4b96a6e9919cfe220156d69a2ede8053d9ea1add4ada108abcf2ba9775"}, + {file = "pulsar_client-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1e4b5d44b992c9b036286b483f3588c10b89c6047fb59d80c7474445997f4e10"}, + {file = "pulsar_client-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:497a59ac6b650835a3b2c502f53477e5c98e5226998ca3f17c0b0a3eb4d67d08"}, + {file = "pulsar_client-3.3.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:386e78ff52058d881780bae1f6e84ac9434ae0b01a8581755ca8cc0dc844a332"}, + {file = "pulsar_client-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e4ecb780df58bcfd3918590bd3ff31ed79bccfbef3a1a60370642eb1e14a9d2"}, + {file = "pulsar_client-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ce1e215c252f22a6f26ca5e9076826041a04d88dc213b92c86b524be2774a64"}, + {file = "pulsar_client-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b0fd5be73a4103986b9dbe3a66468cf8829371e34af87ff8f216e3980f4cbe"}, + {file = "pulsar_client-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33656450536d83eed1563ff09692c2c415fb199d88e9ed97d701ca446a119e1b"}, + {file = "pulsar_client-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:ce33de700b06583df8777e139d68cb4b4b3d0a2eac168d74278d8935f357fb10"}, + {file = "pulsar_client-3.3.0-cp37-cp37m-macosx_10_15_universal2.whl", hash = "sha256:7b5dd25cf778d6c980d36c53081e843ea272afe7af4f0ad6394ae9513f94641b"}, + {file = "pulsar_client-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33c4e6865fda62a2e460f823dce4d49ac2973a4459b8ff99eda5fdd6aaaebf46"}, + {file = "pulsar_client-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1810ddc623c8de2675d17405ce47057a9a2b92298e708ce4d9564847f5ad904"}, + {file = "pulsar_client-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8259c3b856eb6deaa1f93dce893ab18d99d36d102da5612c8e97a4fb41b70ab1"}, + {file = "pulsar_client-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5e7a48b2e505cde758fd51a601b5da0671fa98c9baee38362aaaa3ab2b930c28"}, + {file = "pulsar_client-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ede264385d47257b2f2b08ecde9181ec5338bea5639cc543d1856f01736778d2"}, + {file = "pulsar_client-3.3.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:0f64c62746ccd5b65a0c505f5f40b9af1f147eb1fa2d8f9c90cd5c8b92dd8597"}, + {file = "pulsar_client-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b84a20c9012e3c4ef1b7085acd7467197118c090b378dec27d773fb79d91556"}, + {file = "pulsar_client-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e15fa696e275ccb66d0791fdc19c4dea0420d81349c8055e485b134125e14f"}, + {file = "pulsar_client-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:72cbb1bdcba2dd1265296b5ba65331622ee89c16db75edaad46dd7b90c6dd447"}, + {file = "pulsar_client-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d54dd12955bf587dd46d9184444af5e853d9da2a14bbfb739ed2c7c3b78ce280"}, + {file = "pulsar_client-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:43f98afdf0334b2b957a4d96f97a1fe8a7f7fd1e2631d40c3f00b4162f396485"}, + {file = "pulsar_client-3.3.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:efe7c1e6a96daccc522c3567b6847ffa54c13e0f510d9a427b4aeff9fbebe54b"}, + {file = "pulsar_client-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f28e94420090fceeb38e23fc744f3edf8710e48314ef5927d2b674a1d1e43ee0"}, + {file = "pulsar_client-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c8f3eaa98e2351805ecb6efb6d5fedf47a314a3ce6af0e05ea1449ea7244ed"}, + {file = "pulsar_client-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5e69750f8ae57e55fddf97b459ce0d8b38b2bb85f464a71e871ee6a86d893be7"}, + {file = "pulsar_client-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7e147e5ba460c1818bc05254279a885b4e552bcafb8961d40e31f98d5ff46628"}, + {file = "pulsar_client-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:694530af1d6c75fb81456fb509778c1868adee31e997ddece6e21678200182ea"}, ] [package.dependencies] @@ -3957,8 +2569,6 @@ avro = ["fastavro (==1.7.3)"] functions = ["apache-bookkeeper-client (>=4.16.1)", "grpcio (>=1.8.2)", "prometheus-client", "protobuf (>=3.6.1,<=3.20.3)", "ratelimit"] [[package]] -======= ->>>>>>> second-repo/main name = "pycparser" version = "2.21" description = "C parser in Python" @@ -4012,16 +2622,11 @@ files = [ [[package]] name = "pydantic" -<<<<<<< HEAD version = "1.10.12" -======= -version = "1.10.8" ->>>>>>> second-repo/main description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "pydantic-1.10.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718"}, {file = "pydantic-1.10.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe"}, {file = "pydantic-1.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b"}, @@ -4058,44 +2663,6 @@ files = [ {file = "pydantic-1.10.12-cp39-cp39-win_amd64.whl", hash = "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d"}, {file = "pydantic-1.10.12-py3-none-any.whl", hash = "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942"}, {file = "pydantic-1.10.12.tar.gz", hash = "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303"}, -======= - {file = "pydantic-1.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1243d28e9b05003a89d72e7915fdb26ffd1d39bdd39b00b7dbe4afae4b557f9d"}, - {file = "pydantic-1.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0ab53b609c11dfc0c060d94335993cc2b95b2150e25583bec37a49b2d6c6c3f"}, - {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9613fadad06b4f3bc5db2653ce2f22e0de84a7c6c293909b48f6ed37b83c61f"}, - {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df7800cb1984d8f6e249351139667a8c50a379009271ee6236138a22a0c0f319"}, - {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0c6fafa0965b539d7aab0a673a046466d23b86e4b0e8019d25fd53f4df62c277"}, - {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e82d4566fcd527eae8b244fa952d99f2ca3172b7e97add0b43e2d97ee77f81ab"}, - {file = "pydantic-1.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:ab523c31e22943713d80d8d342d23b6f6ac4b792a1e54064a8d0cf78fd64e800"}, - {file = "pydantic-1.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:666bdf6066bf6dbc107b30d034615d2627e2121506c555f73f90b54a463d1f33"}, - {file = "pydantic-1.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:35db5301b82e8661fa9c505c800d0990bc14e9f36f98932bb1d248c0ac5cada5"}, - {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90c1e29f447557e9e26afb1c4dbf8768a10cc676e3781b6a577841ade126b85"}, - {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e766b4a8226e0708ef243e843105bf124e21331694367f95f4e3b4a92bbb3f"}, - {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88f195f582851e8db960b4a94c3e3ad25692c1c1539e2552f3df7a9e972ef60e"}, - {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:34d327c81e68a1ecb52fe9c8d50c8a9b3e90d3c8ad991bfc8f953fb477d42fb4"}, - {file = "pydantic-1.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:d532bf00f381bd6bc62cabc7d1372096b75a33bc197a312b03f5838b4fb84edd"}, - {file = "pydantic-1.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d5b8641c24886d764a74ec541d2fc2c7fb19f6da2a4001e6d580ba4a38f7878"}, - {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1f6cb446470b7ddf86c2e57cd119a24959af2b01e552f60705910663af09a4"}, - {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33b60054b2136aef8cf190cd4c52a3daa20b2263917c49adad20eaf381e823b"}, - {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1952526ba40b220b912cdc43c1c32bcf4a58e3f192fa313ee665916b26befb68"}, - {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bb14388ec45a7a0dc429e87def6396f9e73c8c77818c927b6a60706603d5f2ea"}, - {file = "pydantic-1.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8c3e33af1e9bb16c7a91fc7d5fa9fe27298e9f299cff6cb744d89d573d62c"}, - {file = "pydantic-1.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ced8375969673929809d7f36ad322934c35de4af3b5e5b09ec967c21f9f7887"}, - {file = "pydantic-1.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93e6bcfccbd831894a6a434b0aeb1947f9e70b7468f274154d03d71fabb1d7c6"}, - {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:191ba419b605f897ede9892f6c56fb182f40a15d309ef0142212200a10af4c18"}, - {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052d8654cb65174d6f9490cc9b9a200083a82cf5c3c5d3985db765757eb3b375"}, - {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ceb6a23bf1ba4b837d0cfe378329ad3f351b5897c8d4914ce95b85fba96da5a1"}, - {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f2e754d5566f050954727c77f094e01793bcb5725b663bf628fa6743a5a9108"}, - {file = "pydantic-1.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:6a82d6cda82258efca32b40040228ecf43a548671cb174a1e81477195ed3ed56"}, - {file = "pydantic-1.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e59417ba8a17265e632af99cc5f35ec309de5980c440c255ab1ca3ae96a3e0e"}, - {file = "pydantic-1.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84d80219c3f8d4cad44575e18404099c76851bc924ce5ab1c4c8bb5e2a2227d0"}, - {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4148e635994d57d834be1182a44bdb07dd867fa3c2d1b37002000646cc5459"}, - {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f7b0bf8553e310e530e9f3a2f5734c68699f42218bf3568ef49cd9b0e44df4"}, - {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42aa0c4b5c3025483240a25b09f3c09a189481ddda2ea3a831a9d25f444e03c1"}, - {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17aef11cc1b997f9d574b91909fed40761e13fac438d72b81f902226a69dac01"}, - {file = "pydantic-1.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:66a703d1983c675a6e0fed8953b0971c44dba48a929a2000a493c3772eb61a5a"}, - {file = "pydantic-1.10.8-py3-none-any.whl", hash = "sha256:7456eb22ed9aaa24ff3e7b4757da20d9e5ce2a81018c1b3ebd81a0b88a18f3b2"}, - {file = "pydantic-1.10.8.tar.gz", hash = "sha256:1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -4107,22 +2674,13 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygments" -<<<<<<< HEAD version = "2.16.1" -======= -version = "2.15.1" ->>>>>>> second-repo/main description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, -======= - {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, - {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, ->>>>>>> second-repo/main ] [package.extras] @@ -4130,22 +2688,13 @@ plugins = ["importlib-metadata"] [[package]] name = "pyjwt" -<<<<<<< HEAD version = "2.8.0" -======= -version = "2.7.0" ->>>>>>> second-repo/main description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, -======= - {file = "PyJWT-2.7.0-py3-none-any.whl", hash = "sha256:ba2b425b15ad5ef12f200dc67dd56af4e26de2331f965c5439994dad075876e1"}, - {file = "PyJWT-2.7.0.tar.gz", hash = "sha256:bd6ca4a3c4285c1a2d4349e5a035fdf8fb94e04ccd0fcbe6ba289dae9cc3e074"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -4158,7 +2707,6 @@ docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] -<<<<<<< HEAD name = "pykx" version = "1.6.3" description = "An interface between Python and q" @@ -4203,37 +2751,6 @@ lint = ["flake8 (==4.0.1)", "flake8-bugbear (==22.1.11)", "flake8-colors (==0.1. pyarrow = ["pyarrow (>=3.0.0,<10.0.0)"] test = ["Cython (==3.0.0a11)", "coverage[toml] (==6.3.2)", "plotly (==5.10.0)", "pytest (==7.1.2)", "pytest-asyncio (==0.18.3)", "pytest-benchmark (==3.4.1)", "pytest-cov (==3.0.0)", "pytest-monitor (==1.6.5)", "pytest-randomly (==3.11.0)", "pytest-xdist (==2.5.0)"] -[[package]] -name = "pymilvus" -version = "2.2.15" -======= -name = "pymilvus" -version = "2.2.8" ->>>>>>> second-repo/main -description = "Python Sdk for Milvus" -optional = false -python-versions = ">=3.7" -files = [ -<<<<<<< HEAD - {file = "pymilvus-2.2.15-py3-none-any.whl", hash = "sha256:2c086a084f7bc34c35da39f3d473e2f91ffe43fc1a88a301f222f3ad09987226"}, - {file = "pymilvus-2.2.15.tar.gz", hash = "sha256:0e618708a64088f476712dfff40c2a3818f775e4c18b6c551cf2dd5d8863063b"}, -======= - {file = "pymilvus-2.2.8-py3-none-any.whl", hash = "sha256:ccf427700c886b3cd73455b40fdac0bf2087243ba1eac5cb6d5745571d1ae467"}, - {file = "pymilvus-2.2.8.tar.gz", hash = "sha256:f866c44a17403a9b7ba681f0c0a28aa8cdecba0f18b8c43f31879d627bd7d1e8"}, ->>>>>>> second-repo/main -] - -[package.dependencies] -environs = "<=9.5.0" -<<<<<<< HEAD -grpcio = ">=1.49.1,<=1.56.0" -======= -grpcio = ">=1.49.1,<=1.53.0" ->>>>>>> second-repo/main -pandas = ">=1.2.4" -protobuf = ">=3.20.0" -ujson = ">=2.0.0" - [[package]] name = "pypdf2" version = "3.0.1" @@ -4265,22 +2782,13 @@ files = [ [[package]] name = "pytest" -<<<<<<< HEAD -version = "7.4.0" -======= -version = "7.3.1" ->>>>>>> second-repo/main +version = "7.4.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, -======= - {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, - {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, ->>>>>>> second-repo/main + {file = "pytest-7.4.1-py3-none-any.whl", hash = "sha256:460c9a59b14e27c602eb5ece2e47bec99dc5fc5f6513cf924a7d03a578991b1f"}, + {file = "pytest-7.4.1.tar.gz", hash = "sha256:2f2301e797521b23e4d2585a0a3d7b5e50fdddaaf7e7d6773ea26ddb17c213ab"}, ] [package.dependencies] @@ -4292,11 +2800,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -<<<<<<< HEAD testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] -======= -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] ->>>>>>> second-repo/main [[package]] name = "pytest-asyncio" @@ -4364,22 +2868,13 @@ cli = ["click (>=5.0)"] [[package]] name = "python-gitlab" -<<<<<<< HEAD version = "3.15.0" -======= -version = "3.14.0" ->>>>>>> second-repo/main description = "Interact with GitLab API" optional = false python-versions = ">=3.7.0" files = [ -<<<<<<< HEAD {file = "python-gitlab-3.15.0.tar.gz", hash = "sha256:c9e65eb7612a9fbb8abf0339972eca7fd7a73d4da66c9b446ffe528930aff534"}, {file = "python_gitlab-3.15.0-py3-none-any.whl", hash = "sha256:8f8d1c0d387f642eb1ac7bf5e8e0cd8b3dd49c6f34170cee3c7deb7d384611f3"}, -======= - {file = "python-gitlab-3.14.0.tar.gz", hash = "sha256:ef3b8960faeee9880f82b0872d807e3fab94ace12b0d2a8418a97875c8812d3c"}, - {file = "python_gitlab-3.14.0-py3-none-any.whl", hash = "sha256:da614c014c6860147783dde8c216218d8fc6bd83a8bd2e3929dcdf11b211aa58"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -4406,17 +2901,18 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc [[package]] name = "python-pptx" -version = "0.6.21" +version = "0.6.22" description = "Generate and manipulate Open XML PowerPoint (.pptx) files" optional = false python-versions = "*" files = [ - {file = "python-pptx-0.6.21.tar.gz", hash = "sha256:7798a2aaf89563565b3c7120c0acfe9aff775db0db3580544e3bf4840c2e378f"}, + {file = "python-pptx-0.6.22.tar.gz", hash = "sha256:38f8ee92dde31d24b4562560e61b0357e5d97ecf75c4352ae6616d5a32978654"}, + {file = "python_pptx-0.6.22-py3-none-any.whl", hash = "sha256:3d097c29e08de2da1fc3c6752169087065efa4153216e77fc1b27dff1bcdcb46"}, ] [package.dependencies] lxml = ">=3.1.0" -Pillow = ">=3.3.2" +Pillow = ">=3.3.2,<=9.5.0" XlsxWriter = ">=0.5.7" [[package]] @@ -4452,22 +2948,13 @@ test = ["coverage (>=5,<6)", "mock (==1.3.0)", "pytest (>=7,<8)", "pytest-mock ( [[package]] name = "pytz" -<<<<<<< HEAD version = "2022.7.1" -======= -version = "2023.3" ->>>>>>> second-repo/main description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ -<<<<<<< HEAD {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, -======= - {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, - {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, ->>>>>>> second-repo/main ] [[package]] @@ -4495,7 +2982,6 @@ files = [ [[package]] name = "pywin32-ctypes" -<<<<<<< HEAD version = "0.2.2" description = "A (partial) reimplementation of pywin32 using ctypes/cffi" optional = false @@ -4503,29 +2989,15 @@ python-versions = ">=3.6" files = [ {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, -======= -version = "0.2.0" -description = "" -optional = false -python-versions = "*" -files = [ - {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, - {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, ->>>>>>> second-repo/main ] [[package]] name = "pyyaml" -<<<<<<< HEAD version = "6.0.1" -======= -version = "6.0" ->>>>>>> second-repo/main description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.6" files = [ -<<<<<<< HEAD {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, @@ -4566,68 +3038,17 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, -======= - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ->>>>>>> second-repo/main ] [[package]] name = "qdrant-client" -<<<<<<< HEAD -version = "1.4.0" -======= -version = "1.1.7" ->>>>>>> second-repo/main +version = "1.5.0" description = "Client library for the Qdrant vector search engine" optional = false -python-versions = ">=3.7,<3.12" +python-versions = ">=3.8,<3.12" files = [ -<<<<<<< HEAD - {file = "qdrant_client-1.4.0-py3-none-any.whl", hash = "sha256:2f9e563955b5163da98016f2ed38d9aea5058576c7c5844e9aa205d28155f56d"}, - {file = "qdrant_client-1.4.0.tar.gz", hash = "sha256:2e54f5a80eb1e7e67f4603b76365af4817af15fb3d0c0f44de4fd93afbbe5537"}, -======= - {file = "qdrant_client-1.1.7-py3-none-any.whl", hash = "sha256:4f5d883660b8193840d8982919ab813a0470ace9a7ff46ee730f909841be5319"}, - {file = "qdrant_client-1.1.7.tar.gz", hash = "sha256:686d86934bec2ebb70676fc0650c9a44a9e552e0149124ca5a22ee8533879deb"}, ->>>>>>> second-repo/main + {file = "qdrant_client-1.5.0-py3-none-any.whl", hash = "sha256:ecfe95f8299c02c9fcb8676966edfd01d081d173f898722d52af3d28b9bbbcf6"}, + {file = "qdrant_client-1.5.0.tar.gz", hash = "sha256:64285465c0d45c8fa871fb10a36ab2da5ed5f163a0f5637925f02f288b5ef906"}, ] [package.dependencies] @@ -4636,17 +3057,11 @@ grpcio-tools = ">=1.41.0" httpx = {version = ">=0.14.0", extras = ["http2"]} numpy = {version = ">=1.21", markers = "python_version >= \"3.8\""} portalocker = ">=2.7.0,<3.0.0" -<<<<<<< HEAD pydantic = ">=1.10.8" -======= -pydantic = ">=1.8,<2.0" -typing-extensions = ">=4.0.0,<5.0.0" ->>>>>>> second-repo/main urllib3 = ">=1.26.14,<2.0.0" [[package]] name = "readme-renderer" -<<<<<<< HEAD version = "41.0" description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse" optional = false @@ -4654,15 +3069,6 @@ python-versions = ">=3.8" files = [ {file = "readme_renderer-41.0-py3-none-any.whl", hash = "sha256:a38243d5b6741b700a850026e62da4bd739edc7422071e95fd5c4bb60171df86"}, {file = "readme_renderer-41.0.tar.gz", hash = "sha256:4f4b11e5893f5a5d725f592c5a343e0dc74f5f273cb3dcf8c42d9703a27073f7"}, -======= -version = "37.3" -description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse" -optional = false -python-versions = ">=3.7" -files = [ - {file = "readme_renderer-37.3-py3-none-any.whl", hash = "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343"}, - {file = "readme_renderer-37.3.tar.gz", hash = "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273"}, ->>>>>>> second-repo/main ] [package.dependencies] @@ -4709,16 +3115,11 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "regex" -<<<<<<< HEAD version = "2023.8.8" -======= -version = "2023.5.5" ->>>>>>> second-repo/main description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.6" files = [ -<<<<<<< HEAD {file = "regex-2023.8.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:88900f521c645f784260a8d346e12a1590f79e96403971241e64c3a265c8ecdb"}, {file = "regex-2023.8.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3611576aff55918af2697410ff0293d6071b7e00f4b09e005d614686ac4cd57c"}, {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8a0ccc8f2698f120e9e5742f4b38dc944c38744d4bdfc427616f3a163dd9de5"}, @@ -4807,101 +3208,10 @@ files = [ {file = "regex-2023.8.8-cp39-cp39-win32.whl", hash = "sha256:6ab2ed84bf0137927846b37e882745a827458689eb969028af8032b1b3dac78e"}, {file = "regex-2023.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5543c055d8ec7801901e1193a51570643d6a6ab8751b1f7dd9af71af467538bb"}, {file = "regex-2023.8.8.tar.gz", hash = "sha256:fcbdc5f2b0f1cd0f6a56cdb46fe41d2cce1e644e3b68832f3eeebc5fb0f7712e"}, -======= - {file = "regex-2023.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:48c9ec56579d4ba1c88f42302194b8ae2350265cb60c64b7b9a88dcb7fbde309"}, - {file = "regex-2023.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f4541550459c08fdd6f97aa4e24c6f1932eec780d58a2faa2068253df7d6ff"}, - {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e22e4460f0245b468ee645156a4f84d0fc35a12d9ba79bd7d79bdcd2f9629d"}, - {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b870b6f632fc74941cadc2a0f3064ed8409e6f8ee226cdfd2a85ae50473aa94"}, - {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:171c52e320fe29260da550d81c6b99f6f8402450dc7777ef5ced2e848f3b6f8f"}, - {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad5524c2aedaf9aa14ef1bc9327f8abd915699dea457d339bebbe2f0d218f86"}, - {file = "regex-2023.5.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a0f874ee8c0bc820e649c900243c6d1e6dc435b81da1492046716f14f1a2a96"}, - {file = "regex-2023.5.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e645c757183ee0e13f0bbe56508598e2d9cd42b8abc6c0599d53b0d0b8dd1479"}, - {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a4c5da39bca4f7979eefcbb36efea04471cd68db2d38fcbb4ee2c6d440699833"}, - {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5e3f4468b8c6fd2fd33c218bbd0a1559e6a6fcf185af8bb0cc43f3b5bfb7d636"}, - {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:59e4b729eae1a0919f9e4c0fc635fbcc9db59c74ad98d684f4877be3d2607dd6"}, - {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ba73a14e9c8f9ac409863543cde3290dba39098fc261f717dc337ea72d3ebad2"}, - {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0bbd5dcb19603ab8d2781fac60114fb89aee8494f4505ae7ad141a3314abb1f9"}, - {file = "regex-2023.5.5-cp310-cp310-win32.whl", hash = "sha256:40005cbd383438aecf715a7b47fe1e3dcbc889a36461ed416bdec07e0ef1db66"}, - {file = "regex-2023.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:59597cd6315d3439ed4b074febe84a439c33928dd34396941b4d377692eca810"}, - {file = "regex-2023.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f08276466fedb9e36e5193a96cb944928301152879ec20c2d723d1031cd4ddd"}, - {file = "regex-2023.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cd46f30e758629c3ee91713529cfbe107ac50d27110fdcc326a42ce2acf4dafc"}, - {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2910502f718828cecc8beff004917dcf577fc5f8f5dd40ffb1ea7612124547b"}, - {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:445d6f4fc3bd9fc2bf0416164454f90acab8858cd5a041403d7a11e3356980e8"}, - {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18196c16a584619c7c1d843497c069955d7629ad4a3fdee240eb347f4a2c9dbe"}, - {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33d430a23b661629661f1fe8395be2004006bc792bb9fc7c53911d661b69dd7e"}, - {file = "regex-2023.5.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72a28979cc667e5f82ef433db009184e7ac277844eea0f7f4d254b789517941d"}, - {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f764e4dfafa288e2eba21231f455d209f4709436baeebb05bdecfb5d8ddc3d35"}, - {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:23d86ad2121b3c4fc78c58f95e19173790e22ac05996df69b84e12da5816cb17"}, - {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:690a17db524ee6ac4a27efc5406530dd90e7a7a69d8360235323d0e5dafb8f5b"}, - {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:1ecf3dcff71f0c0fe3e555201cbe749fa66aae8d18f80d2cc4de8e66df37390a"}, - {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:811040d7f3dd9c55eb0d8b00b5dcb7fd9ae1761c454f444fd9f37fe5ec57143a"}, - {file = "regex-2023.5.5-cp311-cp311-win32.whl", hash = "sha256:c8c143a65ce3ca42e54d8e6fcaf465b6b672ed1c6c90022794a802fb93105d22"}, - {file = "regex-2023.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:586a011f77f8a2da4b888774174cd266e69e917a67ba072c7fc0e91878178a80"}, - {file = "regex-2023.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b6365703e8cf1644b82104cdd05270d1a9f043119a168d66c55684b1b557d008"}, - {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a56c18f21ac98209da9c54ae3ebb3b6f6e772038681d6cb43b8d53da3b09ee81"}, - {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8b942d8b3ce765dbc3b1dad0a944712a89b5de290ce8f72681e22b3c55f3cc8"}, - {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:844671c9c1150fcdac46d43198364034b961bd520f2c4fdaabfc7c7d7138a2dd"}, - {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2ce65bdeaf0a386bb3b533a28de3994e8e13b464ac15e1e67e4603dd88787fa"}, - {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fee0016cc35a8a91e8cc9312ab26a6fe638d484131a7afa79e1ce6165328a135"}, - {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:18f05d14f14a812fe9723f13afafefe6b74ca042d99f8884e62dbd34dcccf3e2"}, - {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:941b3f1b2392f0bcd6abf1bc7a322787d6db4e7457be6d1ffd3a693426a755f2"}, - {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:921473a93bcea4d00295799ab929522fc650e85c6b9f27ae1e6bb32a790ea7d3"}, - {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:e2205a81f815b5bb17e46e74cc946c575b484e5f0acfcb805fb252d67e22938d"}, - {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:385992d5ecf1a93cb85adff2f73e0402dd9ac29b71b7006d342cc920816e6f32"}, - {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:890a09cb0a62198bff92eda98b2b507305dd3abf974778bae3287f98b48907d3"}, - {file = "regex-2023.5.5-cp36-cp36m-win32.whl", hash = "sha256:821a88b878b6589c5068f4cc2cfeb2c64e343a196bc9d7ac68ea8c2a776acd46"}, - {file = "regex-2023.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:7918a1b83dd70dc04ab5ed24c78ae833ae8ea228cef84e08597c408286edc926"}, - {file = "regex-2023.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:338994d3d4ca4cf12f09822e025731a5bdd3a37aaa571fa52659e85ca793fb67"}, - {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a69cf0c00c4d4a929c6c7717fd918414cab0d6132a49a6d8fc3ded1988ed2ea"}, - {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f5e06df94fff8c4c85f98c6487f6636848e1dc85ce17ab7d1931df4a081f657"}, - {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8906669b03c63266b6a7693d1f487b02647beb12adea20f8840c1a087e2dfb5"}, - {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fda3e50abad8d0f48df621cf75adc73c63f7243cbe0e3b2171392b445401550"}, - {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ac2b7d341dc1bd102be849d6dd33b09701223a851105b2754339e390be0627a"}, - {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fb2b495dd94b02de8215625948132cc2ea360ae84fe6634cd19b6567709c8ae2"}, - {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aa7d032c1d84726aa9edeb6accf079b4caa87151ca9fabacef31fa028186c66d"}, - {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3d45864693351c15531f7e76f545ec35000d50848daa833cead96edae1665559"}, - {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21e90a288e6ba4bf44c25c6a946cb9b0f00b73044d74308b5e0afd190338297c"}, - {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:10250a093741ec7bf74bcd2039e697f519b028518f605ff2aa7ac1e9c9f97423"}, - {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6b8d0c153f07a953636b9cdb3011b733cadd4178123ef728ccc4d5969e67f3c2"}, - {file = "regex-2023.5.5-cp37-cp37m-win32.whl", hash = "sha256:10374c84ee58c44575b667310d5bbfa89fb2e64e52349720a0182c0017512f6c"}, - {file = "regex-2023.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9b320677521aabf666cdd6e99baee4fb5ac3996349c3b7f8e7c4eee1c00dfe3a"}, - {file = "regex-2023.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:afb1c70ec1e594a547f38ad6bf5e3d60304ce7539e677c1429eebab115bce56e"}, - {file = "regex-2023.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cf123225945aa58b3057d0fba67e8061c62d14cc8a4202630f8057df70189051"}, - {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a99757ad7fe5c8a2bb44829fc57ced11253e10f462233c1255fe03888e06bc19"}, - {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a623564d810e7a953ff1357f7799c14bc9beeab699aacc8b7ab7822da1e952b8"}, - {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ced02e3bd55e16e89c08bbc8128cff0884d96e7f7a5633d3dc366b6d95fcd1d6"}, - {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cbe6b5be3b9b698d8cc4ee4dee7e017ad655e83361cd0ea8e653d65e469468"}, - {file = "regex-2023.5.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a6e4b0e0531223f53bad07ddf733af490ba2b8367f62342b92b39b29f72735a"}, - {file = "regex-2023.5.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e9c4f778514a560a9c9aa8e5538bee759b55f6c1dcd35613ad72523fd9175b8"}, - {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:256f7f4c6ba145f62f7a441a003c94b8b1af78cee2cccacfc1e835f93bc09426"}, - {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd7b68fd2e79d59d86dcbc1ccd6e2ca09c505343445daaa4e07f43c8a9cc34da"}, - {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4a5059bd585e9e9504ef9c07e4bc15b0a621ba20504388875d66b8b30a5c4d18"}, - {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:6893544e06bae009916a5658ce7207e26ed17385149f35a3125f5259951f1bbe"}, - {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c64d5abe91a3dfe5ff250c6bb267ef00dbc01501518225b45a5f9def458f31fb"}, - {file = "regex-2023.5.5-cp38-cp38-win32.whl", hash = "sha256:7923470d6056a9590247ff729c05e8e0f06bbd4efa6569c916943cb2d9b68b91"}, - {file = "regex-2023.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:4035d6945cb961c90c3e1c1ca2feb526175bcfed44dfb1cc77db4fdced060d3e"}, - {file = "regex-2023.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:50fd2d9b36938d4dcecbd684777dd12a407add4f9f934f235c66372e630772b0"}, - {file = "regex-2023.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d19e57f888b00cd04fc38f5e18d0efbd91ccba2d45039453ab2236e6eec48d4d"}, - {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd966475e963122ee0a7118ec9024388c602d12ac72860f6eea119a3928be053"}, - {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db09e6c18977a33fea26fe67b7a842f706c67cf8bda1450974d0ae0dd63570df"}, - {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6164d4e2a82f9ebd7752a06bd6c504791bedc6418c0196cd0a23afb7f3e12b2d"}, - {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84397d3f750d153ebd7f958efaa92b45fea170200e2df5e0e1fd4d85b7e3f58a"}, - {file = "regex-2023.5.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c3efee9bb53cbe7b285760c81f28ac80dc15fa48b5fe7e58b52752e642553f1"}, - {file = "regex-2023.5.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:144b5b017646b5a9392a5554a1e5db0000ae637be4971c9747566775fc96e1b2"}, - {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1189fbbb21e2c117fda5303653b61905aeeeea23de4a94d400b0487eb16d2d60"}, - {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f83fe9e10f9d0b6cf580564d4d23845b9d692e4c91bd8be57733958e4c602956"}, - {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:72aa4746993a28c841e05889f3f1b1e5d14df8d3daa157d6001a34c98102b393"}, - {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:de2f780c3242ea114dd01f84848655356af4dd561501896c751d7b885ea6d3a1"}, - {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:290fd35219486dfbc00b0de72f455ecdd63e59b528991a6aec9fdfc0ce85672e"}, - {file = "regex-2023.5.5-cp39-cp39-win32.whl", hash = "sha256:732176f5427e72fa2325b05c58ad0b45af341c459910d766f814b0584ac1f9ac"}, - {file = "regex-2023.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:1307aa4daa1cbb23823d8238e1f61292fd07e4e5d8d38a6efff00b67a7cdb764"}, - {file = "regex-2023.5.5.tar.gz", hash = "sha256:7d76a8a1fc9da08296462a18f16620ba73bcbf5909e42383b253ef34d9d5141e"}, ->>>>>>> second-repo/main ] [[package]] name = "requests" -<<<<<<< HEAD version = "2.31.0" description = "Python HTTP for Humans." optional = false @@ -4909,26 +3219,13 @@ python-versions = ">=3.7" files = [ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, -======= -version = "2.28.2" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.7, <4" -files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, ->>>>>>> second-repo/main ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -<<<<<<< HEAD urllib3 = ">=1.21.1,<3" -======= -urllib3 = ">=1.21.1,<1.27" ->>>>>>> second-repo/main [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -4993,34 +3290,19 @@ files = [ [[package]] name = "setuptools" -<<<<<<< HEAD -version = "68.1.2" +version = "68.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, - {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, + {file = "setuptools-68.2.0-py3-none-any.whl", hash = "sha256:af3d5949030c3f493f550876b2fd1dd5ec66689c4ee5d5344f009746f71fd5a8"}, + {file = "setuptools-68.2.0.tar.gz", hash = "sha256:00478ca80aeebeecb2f288d3206b0de568df5cd2b8fada1209843cc9a8d88a48"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -======= -version = "67.8.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, - {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] ->>>>>>> second-repo/main -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -5057,139 +3339,73 @@ files = [ [[package]] name = "sqlalchemy" -<<<<<<< HEAD -version = "2.0.20" -======= -version = "2.0.15" ->>>>>>> second-repo/main +version = "1.4.49" description = "Database Abstraction Library" optional = false -python-versions = ">=3.7" -files = [ -<<<<<<< HEAD - {file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759b51346aa388c2e606ee206c0bc6f15a5299f6174d1e10cadbe4530d3c7a98"}, - {file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1506e988ebeaaf316f183da601f24eedd7452e163010ea63dbe52dc91c7fc70e"}, - {file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5768c268df78bacbde166b48be788b83dddaa2a5974b8810af422ddfe68a9bc8"}, - {file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3f0dd6d15b6dc8b28a838a5c48ced7455c3e1fb47b89da9c79cc2090b072a50"}, - {file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:243d0fb261f80a26774829bc2cee71df3222587ac789b7eaf6555c5b15651eed"}, - {file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6eb6d77c31e1bf4268b4d61b549c341cbff9842f8e115ba6904249c20cb78a61"}, - {file = "SQLAlchemy-2.0.20-cp310-cp310-win32.whl", hash = "sha256:bcb04441f370cbe6e37c2b8d79e4af9e4789f626c595899d94abebe8b38f9a4d"}, - {file = "SQLAlchemy-2.0.20-cp310-cp310-win_amd64.whl", hash = "sha256:d32b5ffef6c5bcb452723a496bad2d4c52b346240c59b3e6dba279f6dcc06c14"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd81466bdbc82b060c3c110b2937ab65ace41dfa7b18681fdfad2f37f27acdd7"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6fe7d61dc71119e21ddb0094ee994418c12f68c61b3d263ebaae50ea8399c4d4"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4e571af672e1bb710b3cc1a9794b55bce1eae5aed41a608c0401885e3491179"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3364b7066b3c7f4437dd345d47271f1251e0cfb0aba67e785343cdbdb0fff08c"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1be86ccea0c965a1e8cd6ccf6884b924c319fcc85765f16c69f1ae7148eba64b"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1d35d49a972649b5080557c603110620a86aa11db350d7a7cb0f0a3f611948a0"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-win32.whl", hash = "sha256:27d554ef5d12501898d88d255c54eef8414576f34672e02fe96d75908993cf53"}, - {file = "SQLAlchemy-2.0.20-cp311-cp311-win_amd64.whl", hash = "sha256:411e7f140200c02c4b953b3dbd08351c9f9818d2bd591b56d0fa0716bd014f1e"}, - {file = "SQLAlchemy-2.0.20-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3c6aceebbc47db04f2d779db03afeaa2c73ea3f8dcd3987eb9efdb987ffa09a3"}, - {file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d3f175410a6db0ad96b10bfbb0a5530ecd4fcf1e2b5d83d968dd64791f810ed"}, - {file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8186be85da6587456c9ddc7bf480ebad1a0e6dcbad3967c4821233a4d4df57"}, - {file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c3d99ba99007dab8233f635c32b5cd24fb1df8d64e17bc7df136cedbea427897"}, - {file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:76fdfc0f6f5341987474ff48e7a66c3cd2b8a71ddda01fa82fedb180b961630a"}, - {file = "SQLAlchemy-2.0.20-cp37-cp37m-win32.whl", hash = "sha256:d3793dcf5bc4d74ae1e9db15121250c2da476e1af8e45a1d9a52b1513a393459"}, - {file = "SQLAlchemy-2.0.20-cp37-cp37m-win_amd64.whl", hash = "sha256:79fde625a0a55220d3624e64101ed68a059c1c1f126c74f08a42097a72ff66a9"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:599ccd23a7146e126be1c7632d1d47847fa9f333104d03325c4e15440fc7d927"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1a58052b5a93425f656675673ef1f7e005a3b72e3f2c91b8acca1b27ccadf5f4"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79543f945be7a5ada9943d555cf9b1531cfea49241809dd1183701f94a748624"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63e73da7fb030ae0a46a9ffbeef7e892f5def4baf8064786d040d45c1d6d1dc5"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ce5e81b800a8afc870bb8e0a275d81957e16f8c4b62415a7b386f29a0cb9763"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb0d3e94c2a84215532d9bcf10229476ffd3b08f481c53754113b794afb62d14"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-win32.whl", hash = "sha256:8dd77fd6648b677d7742d2c3cc105a66e2681cc5e5fb247b88c7a7b78351cf74"}, - {file = "SQLAlchemy-2.0.20-cp38-cp38-win_amd64.whl", hash = "sha256:6f8a934f9dfdf762c844e5164046a9cea25fabbc9ec865c023fe7f300f11ca4a"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:26a3399eaf65e9ab2690c07bd5cf898b639e76903e0abad096cd609233ce5208"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4cde2e1096cbb3e62002efdb7050113aa5f01718035ba9f29f9d89c3758e7e4e"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b09ba72e4e6d341bb5bdd3564f1cea6095d4c3632e45dc69375a1dbe4e26ec"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b74eeafaa11372627ce94e4dc88a6751b2b4d263015b3523e2b1e57291102f0"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:77d37c1b4e64c926fa3de23e8244b964aab92963d0f74d98cbc0783a9e04f501"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eefebcc5c555803065128401a1e224a64607259b5eb907021bf9b175f315d2a6"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-win32.whl", hash = "sha256:3423dc2a3b94125094897118b52bdf4d37daf142cbcf26d48af284b763ab90e9"}, - {file = "SQLAlchemy-2.0.20-cp39-cp39-win_amd64.whl", hash = "sha256:5ed61e3463021763b853628aef8bc5d469fe12d95f82c74ef605049d810f3267"}, - {file = "SQLAlchemy-2.0.20-py3-none-any.whl", hash = "sha256:63a368231c53c93e2b67d0c5556a9836fdcd383f7e3026a39602aad775b14acf"}, - {file = "SQLAlchemy-2.0.20.tar.gz", hash = "sha256:ca8a5ff2aa7f3ade6c498aaafce25b1eaeabe4e42b73e25519183e4566a16fc6"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "SQLAlchemy-1.4.49-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e126cf98b7fd38f1e33c64484406b78e937b1a280e078ef558b95bf5b6895f6"}, + {file = "SQLAlchemy-1.4.49-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:03db81b89fe7ef3857b4a00b63dedd632d6183d4ea5a31c5d8a92e000a41fc71"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:95b9df9afd680b7a3b13b38adf6e3a38995da5e162cc7524ef08e3be4e5ed3e1"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63e43bf3f668c11bb0444ce6e809c1227b8f067ca1068898f3008a273f52b09"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f835c050ebaa4e48b18403bed2c0fda986525896efd76c245bdd4db995e51a4c"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c21b172dfb22e0db303ff6419451f0cac891d2e911bb9fbf8003d717f1bcf91"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-win32.whl", hash = "sha256:5fb1ebdfc8373b5a291485757bd6431de8d7ed42c27439f543c81f6c8febd729"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-win_amd64.whl", hash = "sha256:f8a65990c9c490f4651b5c02abccc9f113a7f56fa482031ac8cb88b70bc8ccaa"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8923dfdf24d5aa8a3adb59723f54118dd4fe62cf59ed0d0d65d940579c1170a4"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9ab2c507a7a439f13ca4499db6d3f50423d1d65dc9b5ed897e70941d9e135b0"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5debe7d49b8acf1f3035317e63d9ec8d5e4d904c6e75a2a9246a119f5f2fdf3d"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-win32.whl", hash = "sha256:82b08e82da3756765c2e75f327b9bf6b0f043c9c3925fb95fb51e1567fa4ee87"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-win_amd64.whl", hash = "sha256:171e04eeb5d1c0d96a544caf982621a1711d078dbc5c96f11d6469169bd003f1"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:36e58f8c4fe43984384e3fbe6341ac99b6b4e083de2fe838f0fdb91cebe9e9cb"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b31e67ff419013f99ad6f8fc73ee19ea31585e1e9fe773744c0f3ce58c039c30"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c14b29d9e1529f99efd550cd04dbb6db6ba5d690abb96d52de2bff4ed518bc95"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c40f3470e084d31247aea228aa1c39bbc0904c2b9ccbf5d3cfa2ea2dac06f26d"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-win32.whl", hash = "sha256:706bfa02157b97c136547c406f263e4c6274a7b061b3eb9742915dd774bbc264"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-win_amd64.whl", hash = "sha256:a7f7b5c07ae5c0cfd24c2db86071fb2a3d947da7bd487e359cc91e67ac1c6d2e"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:4afbbf5ef41ac18e02c8dc1f86c04b22b7a2125f2a030e25bbb4aff31abb224b"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24e300c0c2147484a002b175f4e1361f102e82c345bf263242f0449672a4bccf"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:201de072b818f8ad55c80d18d1a788729cccf9be6d9dc3b9d8613b053cd4836d"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653ed6817c710d0c95558232aba799307d14ae084cc9b1f4c389157ec50df5c"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-win32.whl", hash = "sha256:647e0b309cb4512b1f1b78471fdaf72921b6fa6e750b9f891e09c6e2f0e5326f"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-win_amd64.whl", hash = "sha256:ab73ed1a05ff539afc4a7f8cf371764cdf79768ecb7d2ec691e3ff89abbc541e"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:37ce517c011560d68f1ffb28af65d7e06f873f191eb3a73af5671e9c3fada08a"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1878ce508edea4a879015ab5215546c444233881301e97ca16fe251e89f1c55"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e8e608983e6f85d0852ca61f97e521b62e67969e6e640fe6c6b575d4db68557"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccf956da45290df6e809ea12c54c02ace7f8ff4d765d6d3dfb3655ee876ce58d"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-win32.whl", hash = "sha256:f167c8175ab908ce48bd6550679cc6ea20ae169379e73c7720a28f89e53aa532"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-win_amd64.whl", hash = "sha256:45806315aae81a0c202752558f0df52b42d11dd7ba0097bf71e253b4215f34f4"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b6d0c4b15d65087738a6e22e0ff461b407533ff65a73b818089efc8eb2b3e1de"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a843e34abfd4c797018fd8d00ffffa99fd5184c421f190b6ca99def4087689bd"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c890421651b45a681181301b3497e4d57c0d01dc001e10438a40e9a9c25ee77"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d26f280b8f0a8f497bc10573849ad6dc62e671d2468826e5c748d04ed9e670d5"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-win32.whl", hash = "sha256:ec2268de67f73b43320383947e74700e95c6770d0c68c4e615e9897e46296294"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-win_amd64.whl", hash = "sha256:bbdf16372859b8ed3f4d05f925a984771cd2abd18bd187042f24be4886c2a15f"}, + {file = "SQLAlchemy-1.4.49.tar.gz", hash = "sha256:06ff25cbae30c396c4b7737464f2a7fc37a67b7da409993b182b024cec80aed9"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} -typing-extensions = ">=4.2.0" - -[package.extras] -aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] -======= - {file = "SQLAlchemy-2.0.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78303719c6f72af97814b0072ad18bee72e70adca8d95cf8fecd59c5e1ddb040"}, - {file = "SQLAlchemy-2.0.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9d810b4aacd5ef4e293aa4ea01f19fca53999e9edcfc4a8ef1146238b30bdc28"}, - {file = "SQLAlchemy-2.0.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fb5d09f1d51480f711b69fe28ad42e4f8b08600a85ab2473baee669e1257800"}, - {file = "SQLAlchemy-2.0.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51b19887c96d405599880da6a7cbdf8545a7e78ec5683e46a43bac8885e32d0f"}, - {file = "SQLAlchemy-2.0.15-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6b17cb86908e7f88be14007d6afe7d2ab11966e373044137f96a6a4d83eb21c"}, - {file = "SQLAlchemy-2.0.15-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df25052b92bd514357a9b370d74f240db890ea79aaa428fb893520e10ee5bc18"}, - {file = "SQLAlchemy-2.0.15-cp310-cp310-win32.whl", hash = "sha256:55ec62ddc0200b4fee94d11abbec7aa25948d5d21cb8df8807f4bdd3c51ba44b"}, - {file = "SQLAlchemy-2.0.15-cp310-cp310-win_amd64.whl", hash = "sha256:ae1d8deb391ab39cc8f0d5844e588a115ae3717e607d91482023917f920f777f"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4670ce853cb25f72115a1bbe366ae13cf3f28fc5c87222df14f8d3d55d51816e"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cea7c4a3dfc2ca61f88a2b1ddd6b0bfbd116c9b1a361b3b66fd826034b833142"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f5784dfb2d45c19cde03c45c04a54bf47428610106197ed6e6fa79f33bc63d3"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b31ebde27575b3b0708673ec14f0c305c4564d995b545148ab7ac0f4d9b847a"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b42913a0259267e9ee335da0c36498077799e59c5e332d506e72b4f32de781d"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a3f8020e013e9b3b7941dcf20b0fc8f7429daaf7158760846731cbd8caa5e45"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-win32.whl", hash = "sha256:88ab245ed2c96265441ed2818977be28c840cfa5204ba167425d6c26eb67b7e7"}, - {file = "SQLAlchemy-2.0.15-cp311-cp311-win_amd64.whl", hash = "sha256:5cc48a7fda2b5c5b8860494d6c575db3a101a68416492105fed6591dc8a2728a"}, - {file = "SQLAlchemy-2.0.15-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f6fd3c88ea4b170d13527e93be1945e69facd917661d3725a63470eb683fbffe"}, - {file = "SQLAlchemy-2.0.15-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e885dacb167077df15af2f9ccdacbd7f5dd0d538a6d74b94074f2cefc7bb589"}, - {file = "SQLAlchemy-2.0.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:201a99f922ac8c780b3929128fbd9df901418877c70e160e19adb05665e51c31"}, - {file = "SQLAlchemy-2.0.15-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e17fdcb8971e77c439113642ca8861f9465e21fc693bd3916654ceef3ac26883"}, - {file = "SQLAlchemy-2.0.15-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db269f67ed17b07e80aaa8fba1f650c0d84aa0bdd9d5352e4ac38d5bf47ac568"}, - {file = "SQLAlchemy-2.0.15-cp37-cp37m-win32.whl", hash = "sha256:994a75b197662e0608b6a76935d7c345f7fd874eac0b7093d561033db61b0e8c"}, - {file = "SQLAlchemy-2.0.15-cp37-cp37m-win_amd64.whl", hash = "sha256:4d61731a35eddb0f667774fe15e5a4831e444d066081d1e809e1b8a0e3f97cae"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7f994a53c0e6b44a2966fd6bfc53e37d34b7dca34e75b6be295de6db598255e"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:79bfe728219239bdc493950ea4a4d15b02138ecb304771f9024d0d6f5f4e3706"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6320a1d175447dce63618ec997a53836de48ed3b44bbe952f0b4b399b19941"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f80a9c9a9af0e4bd5080cc0955ce70274c28e9b931ad7e0fb07021afcd32af6"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4a75fdb9a84072521bb2ebd31eefe1165d4dccea3039dda701a864f4b5daa17f"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:21c89044fc48a25c2184eba332edeffbbf9367913bb065cd31538235d828f06f"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-win32.whl", hash = "sha256:1a0754c2d9f0c7982bec0a31138e495ed1f6b8435d7e677c45be60ec18370acf"}, - {file = "SQLAlchemy-2.0.15-cp38-cp38-win_amd64.whl", hash = "sha256:bc5c2b0da46c26c5f73f700834f871d0723e1e882641932468d56833bab09775"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:670ecf74ee2e70b917028a06446ad26ff9b1195e84b09c3139c215123d57dc30"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d14282bf5b4de87f922db3c70858953fd081ef4f05dba6cca3dd705daffe1cc9"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:256b2b9660e51ad7055a9835b12717416cf7288afcf465107413917b6bb2316f"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810199d1c5b43603a9e815ae9487aef3ab1ade7ed9c0c485e12519358929fbfe"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:536c86ec81ca89291d533ff41a3a05f9e4e88e01906dcee0751fc7082f3e8d6c"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:435f6807fa6a0597d84741470f19db204a7d34625ea121abd63e8d95f673f0c4"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-win32.whl", hash = "sha256:da7381a883aee20b7d2ffda17d909b38134b6a625920e65239a1c681881df800"}, - {file = "SQLAlchemy-2.0.15-cp39-cp39-win_amd64.whl", hash = "sha256:788d1772fb8dcd12091ca82809eef504ce0f2c423e45284bc351b872966ff554"}, - {file = "SQLAlchemy-2.0.15-py3-none-any.whl", hash = "sha256:933d30273861fe61f014ce2a7e3c364915f5efe9ed250ec1066ca6ea5942c0bd"}, - {file = "SQLAlchemy-2.0.15.tar.gz", hash = "sha256:2e940a8659ef870ae10e0d9e2a6d5aaddf0ff6e91f7d0d7732afc9e8c4be9bbc"}, -] - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""} -typing-extensions = ">=4.2.0" +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} [package.extras] aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] ->>>>>>> second-repo/main aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)"] -mysql = ["mysqlclient (>=1.4.0)"] +mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] +mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] mysql-connector = ["mysql-connector-python"] -oracle = ["cx-oracle (>=7)"] -oracle-oracledb = ["oracledb (>=1.0.1)"] +oracle = ["cx-oracle (>=7)", "cx-oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.29.1)"] -postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2cffi = ["psycopg2cffi"] -<<<<<<< HEAD -postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] -======= ->>>>>>> second-repo/main -pymysql = ["pymysql"] +pymysql = ["pymysql", "pymysql (<1)"] sqlcipher = ["sqlcipher3-binary"] [[package]] @@ -5211,51 +3427,29 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam [[package]] name = "storage3" -<<<<<<< HEAD version = "0.5.3" -======= -version = "0.5.2" ->>>>>>> second-repo/main description = "Supabase Storage client for Python." optional = false python-versions = ">=3.8,<4.0" files = [ -<<<<<<< HEAD {file = "storage3-0.5.3-py3-none-any.whl", hash = "sha256:5dab88b8e91afadb72fbfde4ce8fb819d6324385624ceb9dca2927fb80b3b800"}, {file = "storage3-0.5.3.tar.gz", hash = "sha256:0c8b356d61eb021d8fcb9ca94d124754f2738c75a73babef91b2f1f60b2a13c0"}, ] [package.dependencies] httpx = ">=0.23,<0.25" -======= - {file = "storage3-0.5.2-py3-none-any.whl", hash = "sha256:3aaba8cebf89eef6b5fc48739b8c8c8539461f2eed9ea1dc4c763dea10c6d009"}, - {file = "storage3-0.5.2.tar.gz", hash = "sha256:e9932fca869a8f9cdab9a20e5249439928cfe2d07c4524141b15fef1882a7f61"}, -] - -[package.dependencies] -httpx = ">=0.23,<0.24" ->>>>>>> second-repo/main python-dateutil = ">=2.8.2,<3.0.0" typing-extensions = ">=4.2.0,<5.0.0" [[package]] name = "strenum" -<<<<<<< HEAD version = "0.4.15" -======= -version = "0.4.10" ->>>>>>> second-repo/main description = "An Enum that inherits from str." optional = false python-versions = "*" files = [ -<<<<<<< HEAD {file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"}, {file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"}, -======= - {file = "StrEnum-0.4.10-py3-none-any.whl", hash = "sha256:aebf04bba8e5af435937c452d69a86798b6f8d5ca5f20ba18561dbfad571ccdd"}, - {file = "StrEnum-0.4.10.tar.gz", hash = "sha256:898cc0ebb5054ee07400341ac1d75fdfee489d76d6df3fbc1c2eaf95971e3916"}, ->>>>>>> second-repo/main ] [package.extras] @@ -5313,7 +3507,6 @@ mpmath = ">=0.19" [[package]] name = "tenacity" -<<<<<<< HEAD version = "8.2.3" description = "Retry code until it succeeds" optional = false @@ -5321,15 +3514,6 @@ python-versions = ">=3.7" files = [ {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, -======= -version = "8.2.2" -description = "Retry code until it succeeds" -optional = false -python-versions = ">=3.6" -files = [ - {file = "tenacity-8.2.2-py3-none-any.whl", hash = "sha256:2f277afb21b851637e8f52e6a613ff08734c347dc19ade928e519d7d2d8569b0"}, - {file = "tenacity-8.2.2.tar.gz", hash = "sha256:43af037822bd0029025877f3b2d97cc4d7bb0c2991000a3d59d71517c5c969e0"}, ->>>>>>> second-repo/main ] [package.extras] @@ -5372,56 +3556,117 @@ requests = ">=2.26.0" [[package]] name = "tokenizers" -version = "0.13.3" -description = "Fast and Customizable Tokenizers" +version = "0.14.0" +description = "" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "tokenizers-0.13.3-cp310-cp310-macosx_10_11_x86_64.whl", hash = "sha256:f3835c5be51de8c0a092058a4d4380cb9244fb34681fd0a295fbf0a52a5fdf33"}, - {file = "tokenizers-0.13.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4ef4c3e821730f2692489e926b184321e887f34fb8a6b80b8096b966ba663d07"}, - {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5fd1a6a25353e9aa762e2aae5a1e63883cad9f4e997c447ec39d071020459bc"}, - {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee0b1b311d65beab83d7a41c56a1e46ab732a9eed4460648e8eb0bd69fc2d059"}, - {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ef4215284df1277dadbcc5e17d4882bda19f770d02348e73523f7e7d8b8d396"}, - {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4d53976079cff8a033f778fb9adca2d9d69d009c02fa2d71a878b5f3963ed30"}, - {file = "tokenizers-0.13.3-cp310-cp310-win32.whl", hash = "sha256:1f0e3b4c2ea2cd13238ce43548959c118069db7579e5d40ec270ad77da5833ce"}, - {file = "tokenizers-0.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:89649c00d0d7211e8186f7a75dfa1db6996f65edce4b84821817eadcc2d3c79e"}, - {file = "tokenizers-0.13.3-cp311-cp311-macosx_10_11_universal2.whl", hash = "sha256:56b726e0d2bbc9243872b0144515ba684af5b8d8cd112fb83ee1365e26ec74c8"}, - {file = "tokenizers-0.13.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:cc5c022ce692e1f499d745af293ab9ee6f5d92538ed2faf73f9708c89ee59ce6"}, - {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f55c981ac44ba87c93e847c333e58c12abcbb377a0c2f2ef96e1a266e4184ff2"}, - {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f247eae99800ef821a91f47c5280e9e9afaeed9980fc444208d5aa6ba69ff148"}, - {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b3e3215d048e94f40f1c95802e45dcc37c5b05eb46280fc2ccc8cd351bff839"}, - {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ba2b0bf01777c9b9bc94b53764d6684554ce98551fec496f71bc5be3a03e98b"}, - {file = "tokenizers-0.13.3-cp311-cp311-win32.whl", hash = "sha256:cc78d77f597d1c458bf0ea7c2a64b6aa06941c7a99cb135b5969b0278824d808"}, - {file = "tokenizers-0.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:ecf182bf59bd541a8876deccf0360f5ae60496fd50b58510048020751cf1724c"}, - {file = "tokenizers-0.13.3-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:0527dc5436a1f6bf2c0327da3145687d3bcfbeab91fed8458920093de3901b44"}, - {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07cbb2c307627dc99b44b22ef05ff4473aa7c7cc1fec8f0a8b37d8a64b1a16d2"}, - {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4560dbdeaae5b7ee0d4e493027e3de6d53c991b5002d7ff95083c99e11dd5ac0"}, - {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64064bd0322405c9374305ab9b4c07152a1474370327499911937fd4a76d004b"}, - {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8c6e2ab0f2e3d939ca66aa1d596602105fe33b505cd2854a4c1717f704c51de"}, - {file = "tokenizers-0.13.3-cp37-cp37m-win32.whl", hash = "sha256:6cc29d410768f960db8677221e497226e545eaaea01aa3613fa0fdf2cc96cff4"}, - {file = "tokenizers-0.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fc2a7fdf864554a0dacf09d32e17c0caa9afe72baf9dd7ddedc61973bae352d8"}, - {file = "tokenizers-0.13.3-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:8791dedba834c1fc55e5f1521be325ea3dafb381964be20684b92fdac95d79b7"}, - {file = "tokenizers-0.13.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:d607a6a13718aeb20507bdf2b96162ead5145bbbfa26788d6b833f98b31b26e1"}, - {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3791338f809cd1bf8e4fee6b540b36822434d0c6c6bc47162448deee3f77d425"}, - {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2f35f30e39e6aab8716f07790f646bdc6e4a853816cc49a95ef2a9016bf9ce6"}, - {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310204dfed5aa797128b65d63538a9837cbdd15da2a29a77d67eefa489edda26"}, - {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0f9b92ea052305166559f38498b3b0cae159caea712646648aaa272f7160963"}, - {file = "tokenizers-0.13.3-cp38-cp38-win32.whl", hash = "sha256:9a3fa134896c3c1f0da6e762d15141fbff30d094067c8f1157b9fdca593b5806"}, - {file = "tokenizers-0.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:8e7b0cdeace87fa9e760e6a605e0ae8fc14b7d72e9fc19c578116f7287bb873d"}, - {file = "tokenizers-0.13.3-cp39-cp39-macosx_10_11_x86_64.whl", hash = "sha256:00cee1e0859d55507e693a48fa4aef07060c4bb6bd93d80120e18fea9371c66d"}, - {file = "tokenizers-0.13.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:a23ff602d0797cea1d0506ce69b27523b07e70f6dda982ab8cf82402de839088"}, - {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ce07445050b537d2696022dafb115307abdffd2a5c106f029490f84501ef97"}, - {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:280ffe95f50eaaf655b3a1dc7ff1d9cf4777029dbbc3e63a74e65a056594abc3"}, - {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97acfcec592f7e9de8cadcdcda50a7134423ac8455c0166b28c9ff04d227b371"}, - {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7730c98a3010cd4f523465867ff95cd9d6430db46676ce79358f65ae39797b"}, - {file = "tokenizers-0.13.3-cp39-cp39-win32.whl", hash = "sha256:48625a108029cb1ddf42e17a81b5a3230ba6888a70c9dc14e81bc319e812652d"}, - {file = "tokenizers-0.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:bc0a6f1ba036e482db6453571c9e3e60ecd5489980ffd95d11dc9f960483d783"}, - {file = "tokenizers-0.13.3.tar.gz", hash = "sha256:2e546dbb68b623008a5442353137fbb0123d311a6d7ba52f2667c8862a75af2e"}, + {file = "tokenizers-0.14.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:1a90e1030d9c61de64045206c62721a36f892dcfc5bbbc119dfcd417c1ca60ca"}, + {file = "tokenizers-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7cacc5a33767bb2a03b6090eac556c301a1d961ac2949be13977bc3f20cc4e3c"}, + {file = "tokenizers-0.14.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81994795e1b4f868a6e73107af8cdf088d31357bae6f7abf26c42874eab16f43"}, + {file = "tokenizers-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ec53f832bfa91abafecbf92b4259b466fb31438ab31e8291ade0fcf07de8fc2"}, + {file = "tokenizers-0.14.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:854aa813a55d6031a6399b1bca09e4e7a79a80ec05faeea77fc6809d59deb3d5"}, + {file = "tokenizers-0.14.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c34d2f02e25e0fa96e574cadb43a6f14bdefc77f84950991da6e3732489e164"}, + {file = "tokenizers-0.14.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f17d5ad725c827d3dc7db2bbe58093a33db2de49bbb639556a6d88d82f0ca19"}, + {file = "tokenizers-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:337a7b7d6b32c6f904faee4304987cb018d1488c88b91aa635760999f5631013"}, + {file = "tokenizers-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:98a7ceb767e1079ef2c99f52a4e7b816f2e682b2b6fef02c8eff5000536e54e1"}, + {file = "tokenizers-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25ad4a0f883a311a5b021ed979e21559cb4184242c7446cd36e07d046d1ed4be"}, + {file = "tokenizers-0.14.0-cp310-none-win32.whl", hash = "sha256:360706b0c2c6ba10e5e26b7eeb7aef106dbfc0a81ad5ad599a892449b4973b10"}, + {file = "tokenizers-0.14.0-cp310-none-win_amd64.whl", hash = "sha256:1c2ce437982717a5e221efa3c546e636f12f325cc3d9d407c91d2905c56593d0"}, + {file = "tokenizers-0.14.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:612d0ba4f40f4d41163af9613dac59c902d017dc4166ea4537a476af807d41c3"}, + {file = "tokenizers-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3013ad0cff561d9be9ce2cc92b76aa746b4e974f20e5b4158c03860a4c8ffe0f"}, + {file = "tokenizers-0.14.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c89a0d6d2ec393a6261df71063b1e22bdd7c6ef3d77b8826541b596132bcf524"}, + {file = "tokenizers-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5514417f37fc2ca8159b27853cd992a9a4982e6c51f04bd3ac3f65f68a8fa781"}, + {file = "tokenizers-0.14.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e761fd1af8409c607b11f084dc7cc50f80f08bd426d4f01d1c353b097d2640f"}, + {file = "tokenizers-0.14.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c16fbcd5ef10df9e51cc84238cdb05ee37e4228aaff39c01aa12b0a0409e29b8"}, + {file = "tokenizers-0.14.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3439d9f858dd9033b69769be5a56eb4fb79fde13fad14fab01edbf2b98033ad9"}, + {file = "tokenizers-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c19f8cdc3e84090464a6e28757f60461388cc8cd41c02c109e180a6b7c571f6"}, + {file = "tokenizers-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:df763ce657a297eb73008d5907243a7558a45ae0930b38ebcb575a24f8296520"}, + {file = "tokenizers-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:095b0b6683a9b76002aa94659f75c09e4359cb291b318d6e77a60965d7a7f138"}, + {file = "tokenizers-0.14.0-cp311-none-win32.whl", hash = "sha256:712ec0e68a399ded8e115e7e25e7017802fa25ee6c36b4eaad88481e50d0c638"}, + {file = "tokenizers-0.14.0-cp311-none-win_amd64.whl", hash = "sha256:917aa6d6615b33d9aa811dcdfb3109e28ff242fbe2cb89ea0b7d3613e444a672"}, + {file = "tokenizers-0.14.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:8464ee7d43ecd9dd1723f51652f49b979052ea3bcd25329e3df44e950c8444d1"}, + {file = "tokenizers-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:84c2b96469b34825557c6fe0bc3154c98d15be58c416a9036ca90afdc9979229"}, + {file = "tokenizers-0.14.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:24b3ccec65ee6f876cd67251c1dcfa1c318c9beec5a438b134f7e33b667a8b36"}, + {file = "tokenizers-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde333fc56dd5fbbdf2de3067d6c0c129867d33eac81d0ba9b65752ad6ef4208"}, + {file = "tokenizers-0.14.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ddcc2f251bd8a2b2f9a7763ad4468a34cfc4ee3b0fba3cfb34d12c964950cac"}, + {file = "tokenizers-0.14.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10a34eb1416dcec3c6f9afea459acd18fcc93234687de605a768a987eda589ab"}, + {file = "tokenizers-0.14.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:56bc7252530a6a20c6eed19b029914bb9cc781efbe943ca9530856051de99d0f"}, + {file = "tokenizers-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07f5c2324326a00c85111081d5eae4da9d64d56abb5883389b3c98bee0b50a7c"}, + {file = "tokenizers-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5efd92e44e43f36332b5f3653743dca5a0b72cdabb012f20023e220f01f675cb"}, + {file = "tokenizers-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9223bcb77a826dbc9fd0efa6bce679a96b1a01005142778bb42ce967581c5951"}, + {file = "tokenizers-0.14.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:e2c1b4707344d3fbfce35d76802c2429ca54e30a5ecb05b3502c1e546039a3bb"}, + {file = "tokenizers-0.14.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:5892ba10fe0a477bde80b9f06bce05cb9d83c15a4676dcae5cbe6510f4524bfc"}, + {file = "tokenizers-0.14.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0e1818f33ac901d5d63830cb6a69a707819f4d958ae5ecb955d8a5ad823a2e44"}, + {file = "tokenizers-0.14.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d06a6fe406df1e616f9e649522683411c6c345ddaaaad7e50bbb60a2cb27e04d"}, + {file = "tokenizers-0.14.0-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b6e2d4bc223dc6a99efbe9266242f1ac03eb0bef0104e6cef9f9512dd5c816b"}, + {file = "tokenizers-0.14.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08ea1f612796e438c9a7e2ad86ab3c1c05c8fe0fad32fcab152c69a3a1a90a86"}, + {file = "tokenizers-0.14.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ab1a58c05a3bd8ece95eb5d1bc909b3fb11acbd3ff514e3cbd1669e3ed28f5b"}, + {file = "tokenizers-0.14.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:495dc7d3b78815de79dafe7abce048a76154dadb0ffc7f09b7247738557e5cef"}, + {file = "tokenizers-0.14.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aaa0401a245d891b3b2ba9cf027dc65ca07627e11fe3ce597644add7d07064f8"}, + {file = "tokenizers-0.14.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae4fa13a786fd0d6549da241c6a1077f9b6320a7120d922ccc201ad1d4feea8f"}, + {file = "tokenizers-0.14.0-cp37-none-win32.whl", hash = "sha256:ae0d5b5ab6032c24a2e74cc15f65b6510070926671129e922aa3826c834558d7"}, + {file = "tokenizers-0.14.0-cp37-none-win_amd64.whl", hash = "sha256:2839369a9eb948905612f5d8e70453267d9c7bf17573e5ab49c2f28368fd635d"}, + {file = "tokenizers-0.14.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:f483af09a07fcb8b8b4cd07ac1be9f58bb739704ef9156e955531299ab17ec75"}, + {file = "tokenizers-0.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9c2ec661d0d63e618cb145ad15ddb6a81e16d9deb7a203f385d78141da028984"}, + {file = "tokenizers-0.14.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:97e87eb7cbeff63c3b1aa770fdcf18ea4f1c852bfb75d0c913e71b8924a99d61"}, + {file = "tokenizers-0.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98c4bd09b47f77f41785488971543de63db82608f0dc0bc6646c876b5ca44d1f"}, + {file = "tokenizers-0.14.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0cbeb5406be31f7605d032bb261f2e728da8ac1f4f196c003bc640279ceb0f52"}, + {file = "tokenizers-0.14.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe799fa48fd7dd549a68abb7bee32dd3721f50210ad2e3e55058080158c72c25"}, + {file = "tokenizers-0.14.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:66daf7c6375a95970e86cb3febc48becfeec4e38b2e0195218d348d3bb86593b"}, + {file = "tokenizers-0.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b177422af79a77c46bb8f56d73827e688fdc092878cff54e24f5c07a908db"}, + {file = "tokenizers-0.14.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a9aef7a5622648b70f979e96cbc2f795eba5b28987dd62f4dbf8f1eac6d64a1a"}, + {file = "tokenizers-0.14.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:397a24feff284d39b40fdd61c1c828bb6648dfe97b6766c84fbaf7256e272d09"}, + {file = "tokenizers-0.14.0-cp38-none-win32.whl", hash = "sha256:93cc2ec19b6ff6149b2e5127ceda3117cc187dd38556a1ed93baba13dffda069"}, + {file = "tokenizers-0.14.0-cp38-none-win_amd64.whl", hash = "sha256:bf7f540ab8a6fc53fb762963edb7539b11f00af8f70b206f0a6d1a25109ad307"}, + {file = "tokenizers-0.14.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a58d0b34586f4c5229de5aa124cf76b9455f2e01dc5bd6ed018f6e3bb12572d3"}, + {file = "tokenizers-0.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:90ceca6a06bb4b0048d0a51d0d47ef250d3cb37cc36b6b43334be8c02ac18b0f"}, + {file = "tokenizers-0.14.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5f6c9554bda64799b1d65052d834553bff9a6ef4a6c2114668e2ed8f1871a2a3"}, + {file = "tokenizers-0.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ee14b41024bc05ea172fc2c87f66b60d7c5c636c3a52a09a25ec18e752e6dc7"}, + {file = "tokenizers-0.14.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:879201b1c76b24dc70ce02fc42c3eeb7ff20c353ce0ee638be6449f7c80e73ba"}, + {file = "tokenizers-0.14.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca79ea6ddde5bb32f7ad1c51de1032829c531e76bbcae58fb3ed105a31faf021"}, + {file = "tokenizers-0.14.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd5934048e60aedddf6c5b076d44ccb388702e1650e2eb7b325a1682d883fbf9"}, + {file = "tokenizers-0.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1566cabd4bf8f09d6c1fa7a3380a181801a495e7218289dbbd0929de471711"}, + {file = "tokenizers-0.14.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a8fc72a7adc6fa12db38100c403d659bc01fbf6e57f2cc9219e75c4eb0ea313c"}, + {file = "tokenizers-0.14.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7fd08ed6c14aa285482d9e5f48c04de52bdbcecaca0d30465d7a36bbea6b14df"}, + {file = "tokenizers-0.14.0-cp39-none-win32.whl", hash = "sha256:3279c0c1d5fdea7d3499c582fed392fb0463d1046544ca010f53aeee5d2ce12c"}, + {file = "tokenizers-0.14.0-cp39-none-win_amd64.whl", hash = "sha256:203ca081d25eb6e4bc72ea04d552e457079c5c6a3713715ece246f6ca02ca8d0"}, + {file = "tokenizers-0.14.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:b45704d5175499387e33a1dd5c8d49ab4d7ef3c36a9ba8a410bb3e68d10f80a0"}, + {file = "tokenizers-0.14.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6d17d5eb38ccc2f615a7a3692dfa285abe22a1e6d73bbfd753599e34ceee511c"}, + {file = "tokenizers-0.14.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4a7e6e7989ba77a20c33f7a8a45e0f5b3e7530b2deddad2c3b2a58b323156134"}, + {file = "tokenizers-0.14.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81876cefea043963abf6c92e0cf73ce6ee10bdc43245b6565ce82c0305c2e613"}, + {file = "tokenizers-0.14.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d8cd05f73d1ce875a23bfdb3a572417c0f46927c6070ca43a7f6f044c3d6605"}, + {file = "tokenizers-0.14.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:419a38b89be0081d872eac09449c03cd6589c2ee47461184592ee4b1ad93af1d"}, + {file = "tokenizers-0.14.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4caf274a9ba944eb83bc695beef95abe24ce112907fb06217875894d8a4f62b8"}, + {file = "tokenizers-0.14.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:6ecb3a7741d7ebf65db93d246b102efca112860707e07233f1b88703cb01dbc5"}, + {file = "tokenizers-0.14.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cb7fe9a383cb2932848e459d0277a681d58ad31aa6ccda204468a8d130a9105c"}, + {file = "tokenizers-0.14.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4731e0577780d85788ab4f00d54e16e76fe305739396e6fb4c54b89e6fa12de"}, + {file = "tokenizers-0.14.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9900291ccd19417128e328a26672390365dab1d230cd00ee7a5e2a0319e2716"}, + {file = "tokenizers-0.14.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:493e6932fbca6875fd2e51958f1108ce4c5ae41aa6f2b8017c5f07beaff0a1ac"}, + {file = "tokenizers-0.14.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1792e6b46b89aba0d501c0497f38c96e5b54735379fd8a07a28f45736ba51bb1"}, + {file = "tokenizers-0.14.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0af26d37c7080688ef606679f3a3d44b63b881de9fa00cc45adc240ba443fd85"}, + {file = "tokenizers-0.14.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:99379ec4d7023c07baed85c68983bfad35fd210dfbc256eaafeb842df7f888e3"}, + {file = "tokenizers-0.14.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:84118aa60dcbb2686730342a0cb37e54e02fde001f936557223d46b6cd8112cd"}, + {file = "tokenizers-0.14.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d616e1859ffcc8fcda60f556c34338b96fb72ca642f6dafc3b1d2aa1812fb4dd"}, + {file = "tokenizers-0.14.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7826b79bbbffc2150bf8d621297cc600d8a1ea53992547c4fd39630de10466b4"}, + {file = "tokenizers-0.14.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eb3931d734f1e66b77c2a8e22ebe0c196f127c7a0f48bf9601720a6f85917926"}, + {file = "tokenizers-0.14.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:6a475b5cafc7a740bf33d00334b1f2b434b6124198384d8b511931a891be39ff"}, + {file = "tokenizers-0.14.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:3d3c9e286ae00b0308903d2ef7b31efc84358109aa41abaa27bd715401c3fef4"}, + {file = "tokenizers-0.14.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:27244e96810434cf705f317e9b74a1163cd2be20bdbd3ed6b96dae1914a6778c"}, + {file = "tokenizers-0.14.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ca9b0536fd5f03f62427230e85d9d57f9eed644ab74c319ae4877c9144356aed"}, + {file = "tokenizers-0.14.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f64cdff8c0454295b739d77e25cff7264fa9822296395e60cbfecc7f66d88fb"}, + {file = "tokenizers-0.14.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a00cdfb40544656b7a3b176049d63227d5e53cf2574912514ebb4b9da976aaa1"}, + {file = "tokenizers-0.14.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:b611d96b96957cb2f39560c77cc35d2fcb28c13d5b7d741412e0edfdb6f670a8"}, + {file = "tokenizers-0.14.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:27ad1c02fdd74dcf3502fafb87393412e65f698f2e3aba4ad568a1f3b43d5c9f"}, + {file = "tokenizers-0.14.0.tar.gz", hash = "sha256:a06efa1f19dcc0e9bd0f4ffbf963cb0217af92a9694f68fe7eee5e1c6ddc4bde"}, ] +[package.dependencies] +huggingface_hub = ">=0.16.4,<0.17" + [package.extras] -dev = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] -docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] +dev = ["tokenizers[testing]"] +docs = ["setuptools_rust", "sphinx", "sphinx_rtd_theme"] testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] [[package]] @@ -5437,53 +3682,31 @@ files = [ [[package]] name = "tomlkit" -<<<<<<< HEAD version = "0.12.1" -======= -version = "0.11.8" ->>>>>>> second-repo/main description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, -======= - {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, - {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, ->>>>>>> second-repo/main ] [[package]] name = "tqdm" -<<<<<<< HEAD version = "4.66.1" -======= -version = "4.65.0" ->>>>>>> second-repo/main description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, -======= - {file = "tqdm-4.65.0-py3-none-any.whl", hash = "sha256:c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671"}, - {file = "tqdm-4.65.0.tar.gz", hash = "sha256:1871fb68a86b8fb3b59ca4cdd3dcccbc7e6d613eeed31f4c332531977b89beb5"}, ->>>>>>> second-repo/main ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -<<<<<<< HEAD dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] -======= -dev = ["py-make (>=0.1.0)", "twine", "wheel"] ->>>>>>> second-repo/main notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] @@ -5513,22 +3736,13 @@ urllib3 = ">=1.26.0" [[package]] name = "typing-extensions" -<<<<<<< HEAD version = "4.7.1" -======= -version = "4.6.2" ->>>>>>> second-repo/main description = "Backported and Experimental Type Hints for Python 3.7+" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, -======= - {file = "typing_extensions-4.6.2-py3-none-any.whl", hash = "sha256:3a8b36f13dd5fdc5d1b16fe317f5668545de77fa0b8e02006381fd49d731ab98"}, - {file = "typing_extensions-4.6.2.tar.gz", hash = "sha256:06006244c70ac8ee83fa8282cb188f697b8db25bc8b4df07be1873c43897060c"}, ->>>>>>> second-repo/main ] [[package]] @@ -5546,161 +3760,6 @@ files = [ mypy-extensions = ">=0.3.0" typing-extensions = ">=3.7.4" -[[package]] -<<<<<<< HEAD -name = "ujson" -version = "5.8.0" -description = "Ultra fast JSON encoder and decoder for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "ujson-5.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4511560d75b15ecb367eef561554959b9d49b6ec3b8d5634212f9fed74a6df1"}, - {file = "ujson-5.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9399eaa5d1931a0ead49dce3ffacbea63f3177978588b956036bfe53cdf6af75"}, - {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4e7bb7eba0e1963f8b768f9c458ecb193e5bf6977090182e2b4f4408f35ac76"}, - {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40931d7c08c4ce99adc4b409ddb1bbb01635a950e81239c2382cfe24251b127a"}, - {file = "ujson-5.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d53039d39de65360e924b511c7ca1a67b0975c34c015dd468fca492b11caa8f7"}, - {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bdf04c6af3852161be9613e458a1fb67327910391de8ffedb8332e60800147a2"}, - {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a70f776bda2e5072a086c02792c7863ba5833d565189e09fabbd04c8b4c3abba"}, - {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f26629ac531d712f93192c233a74888bc8b8212558bd7d04c349125f10199fcf"}, - {file = "ujson-5.8.0-cp310-cp310-win32.whl", hash = "sha256:7ecc33b107ae88405aebdb8d82c13d6944be2331ebb04399134c03171509371a"}, - {file = "ujson-5.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b27a8da7a080add559a3b73ec9ebd52e82cc4419f7c6fb7266e62439a055ed0"}, - {file = "ujson-5.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:193349a998cd821483a25f5df30b44e8f495423840ee11b3b28df092ddfd0f7f"}, - {file = "ujson-5.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ddeabbc78b2aed531f167d1e70387b151900bc856d61e9325fcdfefb2a51ad8"}, - {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ce24909a9c25062e60653073dd6d5e6ec9d6ad7ed6e0069450d5b673c854405"}, - {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27a2a3c7620ebe43641e926a1062bc04e92dbe90d3501687957d71b4bdddaec4"}, - {file = "ujson-5.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b852bdf920fe9f84e2a2c210cc45f1b64f763b4f7d01468b33f7791698e455e"}, - {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:20768961a6a706170497129960762ded9c89fb1c10db2989c56956b162e2a8a3"}, - {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e0147d41e9fb5cd174207c4a2895c5e24813204499fd0839951d4c8784a23bf5"}, - {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e3673053b036fd161ae7a5a33358ccae6793ee89fd499000204676baafd7b3aa"}, - {file = "ujson-5.8.0-cp311-cp311-win32.whl", hash = "sha256:a89cf3cd8bf33a37600431b7024a7ccf499db25f9f0b332947fbc79043aad879"}, - {file = "ujson-5.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3659deec9ab9eb19e8646932bfe6fe22730757c4addbe9d7d5544e879dc1b721"}, - {file = "ujson-5.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:102bf31c56f59538cccdfec45649780ae00657e86247c07edac434cb14d5388c"}, - {file = "ujson-5.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:299a312c3e85edee1178cb6453645217ba23b4e3186412677fa48e9a7f986de6"}, - {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e385a7679b9088d7bc43a64811a7713cc7c33d032d020f757c54e7d41931ae"}, - {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad24ec130855d4430a682c7a60ca0bc158f8253ec81feed4073801f6b6cb681b"}, - {file = "ujson-5.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16fde596d5e45bdf0d7de615346a102510ac8c405098e5595625015b0d4b5296"}, - {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6d230d870d1ce03df915e694dcfa3f4e8714369cce2346686dbe0bc8e3f135e7"}, - {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9571de0c53db5cbc265945e08f093f093af2c5a11e14772c72d8e37fceeedd08"}, - {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7cba16b26efe774c096a5e822e4f27097b7c81ed6fb5264a2b3f5fd8784bab30"}, - {file = "ujson-5.8.0-cp312-cp312-win32.whl", hash = "sha256:48c7d373ff22366eecfa36a52b9b55b0ee5bd44c2b50e16084aa88b9de038916"}, - {file = "ujson-5.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:5ac97b1e182d81cf395ded620528c59f4177eee024b4b39a50cdd7b720fdeec6"}, - {file = "ujson-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2a64cc32bb4a436e5813b83f5aab0889927e5ea1788bf99b930fad853c5625cb"}, - {file = "ujson-5.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e54578fa8838ddc722539a752adfce9372474114f8c127bb316db5392d942f8b"}, - {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9721cd112b5e4687cb4ade12a7b8af8b048d4991227ae8066d9c4b3a6642a582"}, - {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9707e5aacf63fb919f6237d6490c4e0244c7f8d3dc2a0f84d7dec5db7cb54c"}, - {file = "ujson-5.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0be81bae295f65a6896b0c9030b55a106fb2dec69ef877253a87bc7c9c5308f7"}, - {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae7f4725c344bf437e9b881019c558416fe84ad9c6b67426416c131ad577df67"}, - {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9ab282d67ef3097105552bf151438b551cc4bedb3f24d80fada830f2e132aeb9"}, - {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94c7bd9880fa33fcf7f6d7f4cc032e2371adee3c5dba2922b918987141d1bf07"}, - {file = "ujson-5.8.0-cp38-cp38-win32.whl", hash = "sha256:bf5737dbcfe0fa0ac8fa599eceafae86b376492c8f1e4b84e3adf765f03fb564"}, - {file = "ujson-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:11da6bed916f9bfacf13f4fc6a9594abd62b2bb115acfb17a77b0f03bee4cfd5"}, - {file = "ujson-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:69b3104a2603bab510497ceabc186ba40fef38ec731c0ccaa662e01ff94a985c"}, - {file = "ujson-5.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9249fdefeb021e00b46025e77feed89cd91ffe9b3a49415239103fc1d5d9c29a"}, - {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2873d196725a8193f56dde527b322c4bc79ed97cd60f1d087826ac3290cf9207"}, - {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4dafa9010c366589f55afb0fd67084acd8added1a51251008f9ff2c3e44042"}, - {file = "ujson-5.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a42baa647a50fa8bed53d4e242be61023bd37b93577f27f90ffe521ac9dc7a3"}, - {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f3554eaadffe416c6f543af442066afa6549edbc34fe6a7719818c3e72ebfe95"}, - {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fb87decf38cc82bcdea1d7511e73629e651bdec3a43ab40985167ab8449b769c"}, - {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:407d60eb942c318482bbfb1e66be093308bb11617d41c613e33b4ce5be789adc"}, - {file = "ujson-5.8.0-cp39-cp39-win32.whl", hash = "sha256:0fe1b7edaf560ca6ab023f81cbeaf9946a240876a993b8c5a21a1c539171d903"}, - {file = "ujson-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f9b63530a5392eb687baff3989d0fb5f45194ae5b1ca8276282fb647f8dcdb3"}, - {file = "ujson-5.8.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:efeddf950fb15a832376c0c01d8d7713479fbeceaed1eaecb2665aa62c305aec"}, - {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d8283ac5d03e65f488530c43d6610134309085b71db4f675e9cf5dff96a8282"}, - {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb0142f6f10f57598655340a3b2c70ed4646cbe674191da195eb0985a9813b83"}, - {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d459aca895eb17eb463b00441986b021b9312c6c8cc1d06880925c7f51009c"}, - {file = "ujson-5.8.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d524a8c15cfc863705991d70bbec998456a42c405c291d0f84a74ad7f35c5109"}, - {file = "ujson-5.8.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d6f84a7a175c75beecde53a624881ff618e9433045a69fcfb5e154b73cdaa377"}, - {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b748797131ac7b29826d1524db1cc366d2722ab7afacc2ce1287cdafccddbf1f"}, - {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e72ba76313d48a1a3a42e7dc9d1db32ea93fac782ad8dde6f8b13e35c229130"}, - {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f504117a39cb98abba4153bf0b46b4954cc5d62f6351a14660201500ba31fe7f"}, - {file = "ujson-5.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8c91b6f4bf23f274af9002b128d133b735141e867109487d17e344d38b87d94"}, - {file = "ujson-5.8.0.tar.gz", hash = "sha256:78e318def4ade898a461b3d92a79f9441e7e0e4d2ad5419abed4336d702c7425"}, -======= -name = "tzdata" -version = "2023.3" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, -] - -[[package]] -name = "ujson" -version = "5.7.0" -description = "Ultra fast JSON encoder and decoder for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "ujson-5.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5eba5e69e4361ac3a311cf44fa71bc619361b6e0626768a494771aacd1c2f09b"}, - {file = "ujson-5.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aae4d9e1b4c7b61780f0a006c897a4a1904f862fdab1abb3ea8f45bd11aa58f3"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2e43ccdba1cb5c6d3448eadf6fc0dae7be6c77e357a3abc968d1b44e265866d"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54384ce4920a6d35fa9ea8e580bc6d359e3eb961fa7e43f46c78e3ed162d56ff"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24ad1aa7fc4e4caa41d3d343512ce68e41411fb92adf7f434a4d4b3749dc8f58"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:afff311e9f065a8f03c3753db7011bae7beb73a66189c7ea5fcb0456b7041ea4"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e80f0d03e7e8646fc3d79ed2d875cebd4c83846e129737fdc4c2532dbd43d9e"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:137831d8a0db302fb6828ee21c67ad63ac537bddc4376e1aab1c8573756ee21c"}, - {file = "ujson-5.7.0-cp310-cp310-win32.whl", hash = "sha256:7df3fd35ebc14dafeea031038a99232b32f53fa4c3ecddb8bed132a43eefb8ad"}, - {file = "ujson-5.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:af4639f684f425177d09ae409c07602c4096a6287027469157bfb6f83e01448b"}, - {file = "ujson-5.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b0f2680ce8a70f77f5d70aaf3f013d53e6af6d7058727a35d8ceb4a71cdd4e9"}, - {file = "ujson-5.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a19fd8e7d8cc58a169bea99fed5666023adf707a536d8f7b0a3c51dd498abf"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6abb8e6d8f1ae72f0ed18287245f5b6d40094e2656d1eab6d99d666361514074"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8cd622c069368d5074bd93817b31bdb02f8d818e57c29e206f10a1f9c6337dd"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14f9082669f90e18e64792b3fd0bf19f2b15e7fe467534a35ea4b53f3bf4b755"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7ff6ebb43bc81b057724e89550b13c9a30eda0f29c2f506f8b009895438f5a6"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f7f241488879d91a136b299e0c4ce091996c684a53775e63bb442d1a8e9ae22a"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5593263a7fcfb934107444bcfba9dde8145b282de0ee9f61e285e59a916dda0f"}, - {file = "ujson-5.7.0-cp311-cp311-win32.whl", hash = "sha256:26c2b32b489c393106e9cb68d0a02e1a7b9d05a07429d875c46b94ee8405bdb7"}, - {file = "ujson-5.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:ed24406454bb5a31df18f0a423ae14beb27b28cdfa34f6268e7ebddf23da807e"}, - {file = "ujson-5.7.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18679484e3bf9926342b1c43a3bd640f93a9eeeba19ef3d21993af7b0c44785d"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee295761e1c6c30400641f0a20d381633d7622633cdf83a194f3c876a0e4b7e"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b738282e12a05f400b291966630a98d622da0938caa4bc93cf65adb5f4281c60"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00343501dbaa5172e78ef0e37f9ebd08040110e11c12420ff7c1f9f0332d939e"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c0d1f7c3908357ee100aa64c4d1cf91edf99c40ac0069422a4fd5fd23b263263"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a5d2f44331cf04689eafac7a6596c71d6657967c07ac700b0ae1c921178645da"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:16b2254a77b310f118717715259a196662baa6b1f63b1a642d12ab1ff998c3d7"}, - {file = "ujson-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:6faf46fa100b2b89e4db47206cf8a1ffb41542cdd34dde615b2fc2288954f194"}, - {file = "ujson-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ff0004c3f5a9a6574689a553d1b7819d1a496b4f005a7451f339dc2d9f4cf98c"}, - {file = "ujson-5.7.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:75204a1dd7ec6158c8db85a2f14a68d2143503f4bafb9a00b63fe09d35762a5e"}, - {file = "ujson-5.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7312731c7826e6c99cdd3ac503cd9acd300598e7a80bcf41f604fee5f49f566c"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b9dc5a90e2149643df7f23634fe202fed5ebc787a2a1be95cf23632b4d90651"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6a6961fc48821d84b1198a09516e396d56551e910d489692126e90bf4887d29"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b01a9af52a0d5c46b2c68e3f258fdef2eacaa0ce6ae3e9eb97983f5b1166edb6"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7316d3edeba8a403686cdcad4af737b8415493101e7462a70ff73dd0609eafc"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ee997799a23227e2319a3f8817ce0b058923dbd31904761b788dc8f53bd3e30"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dda9aa4c33435147262cd2ea87c6b7a1ca83ba9b3933ff7df34e69fee9fced0c"}, - {file = "ujson-5.7.0-cp38-cp38-win32.whl", hash = "sha256:bea8d30e362180aafecabbdcbe0e1f0b32c9fa9e39c38e4af037b9d3ca36f50c"}, - {file = "ujson-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:c96e3b872bf883090ddf32cc41957edf819c5336ab0007d0cf3854e61841726d"}, - {file = "ujson-5.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6411aea4c94a8e93c2baac096fbf697af35ba2b2ed410b8b360b3c0957a952d3"}, - {file = "ujson-5.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d3b3499c55911f70d4e074c626acdb79a56f54262c3c83325ffb210fb03e44d"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:341f891d45dd3814d31764626c55d7ab3fd21af61fbc99d070e9c10c1190680b"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f242eec917bafdc3f73a1021617db85f9958df80f267db69c76d766058f7b19"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3af9f9f22a67a8c9466a32115d9073c72a33ae627b11de6f592df0ee09b98b6"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a3d794afbf134df3056a813e5c8a935208cddeae975bd4bc0ef7e89c52f0ce0"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:800bf998e78dae655008dd10b22ca8dc93bdcfcc82f620d754a411592da4bbf2"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b5ac3d5c5825e30b438ea92845380e812a476d6c2a1872b76026f2e9d8060fc2"}, - {file = "ujson-5.7.0-cp39-cp39-win32.whl", hash = "sha256:cd90027e6d93e8982f7d0d23acf88c896d18deff1903dd96140613389b25c0dd"}, - {file = "ujson-5.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:523ee146cdb2122bbd827f4dcc2a8e66607b3f665186bce9e4f78c9710b6d8ab"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e87cec407ec004cf1b04c0ed7219a68c12860123dfb8902ef880d3d87a71c172"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bab10165db6a7994e67001733f7f2caf3400b3e11538409d8756bc9b1c64f7e8"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b522be14a28e6ac1cf818599aeff1004a28b42df4ed4d7bc819887b9dac915fc"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7592f40175c723c032cdbe9fe5165b3b5903604f774ab0849363386e99e1f253"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ed22f9665327a981f288a4f758a432824dc0314e4195a0eaeb0da56a477da94d"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:adf445a49d9a97a5a4c9bb1d652a1528de09dd1c48b29f79f3d66cea9f826bf6"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64772a53f3c4b6122ed930ae145184ebaed38534c60f3d859d8c3f00911eb122"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35209cb2c13fcb9d76d249286105b4897b75a5e7f0efb0c0f4b90f222ce48910"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90712dfc775b2c7a07d4d8e059dd58636bd6ff1776d79857776152e693bddea6"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0e4e8981c6e7e9e637e637ad8ffe948a09e5434bc5f52ecbb82b4b4cfc092bfb"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:581c945b811a3d67c27566539bfcb9705ea09cb27c4be0002f7a553c8886b817"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d36a807a24c7d44f71686685ae6fbc8793d784bca1adf4c89f5f780b835b6243"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b4257307e3662aa65e2644a277ca68783c5d51190ed9c49efebdd3cbfd5fa44"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea7423d8a2f9e160c5e011119741682414c5b8dce4ae56590a966316a07a4618"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c592eb91a5968058a561d358d0fef59099ed152cfb3e1cd14eee51a7a93879e"}, - {file = "ujson-5.7.0.tar.gz", hash = "sha256:e788e5d5dcae8f6118ac9b45d0b891a0d55f7ac480eddcb7f07263f2bcf37b23"}, ->>>>>>> second-repo/main -] - [[package]] name = "urllib3" version = "1.26.16" @@ -5788,7 +3847,6 @@ test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "my [[package]] name = "validators" -<<<<<<< HEAD version = "0.21.0" description = "Python Data Validation for Humans™" optional = false @@ -5798,51 +3856,35 @@ files = [ {file = "validators-0.21.0.tar.gz", hash = "sha256:245b98ab778ed9352a7269c6a8f6c2a839bed5b2a7e3e60273ce399d247dd4b3"}, ] -======= -version = "0.20.0" -description = "Python Data Validation for Humans™." -optional = false -python-versions = ">=3.4" -files = [ - {file = "validators-0.20.0.tar.gz", hash = "sha256:24148ce4e64100a2d5e267233e23e7afeb55316b47d30faae7eb6e7292bc226a"}, -] - -[package.dependencies] -decorator = ">=3.4.0" - -[package.extras] -test = ["flake8 (>=2.4.0)", "isort (>=4.2.2)", "pytest (>=2.2.3)"] - ->>>>>>> second-repo/main [[package]] name = "watchfiles" -version = "0.19.0" +version = "0.20.0" description = "Simple, modern and high performance file watching and code reload in python." optional = false python-versions = ">=3.7" files = [ - {file = "watchfiles-0.19.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:91633e64712df3051ca454ca7d1b976baf842d7a3640b87622b323c55f3345e7"}, - {file = "watchfiles-0.19.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b6577b8c6c8701ba8642ea9335a129836347894b666dd1ec2226830e263909d3"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18b28f6ad871b82df9542ff958d0c86bb0d8310bb09eb8e87d97318a3b5273af"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac19dc9cbc34052394dbe81e149411a62e71999c0a19e1e09ce537867f95ae0"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ea3397aecbc81c19ed7f025e051a7387feefdb789cf768ff994c1228182fda"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0376deac92377817e4fb8f347bf559b7d44ff556d9bc6f6208dd3f79f104aaf"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c75eff897786ee262c9f17a48886f4e98e6cfd335e011c591c305e5d083c056"}, - {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb5d45c4143c1dd60f98a16187fd123eda7248f84ef22244818c18d531a249d1"}, - {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:79c533ff593db861ae23436541f481ec896ee3da4e5db8962429b441bbaae16e"}, - {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3d7d267d27aceeeaa3de0dd161a0d64f0a282264d592e335fff7958cc0cbae7c"}, - {file = "watchfiles-0.19.0-cp37-abi3-win32.whl", hash = "sha256:176a9a7641ec2c97b24455135d58012a5be5c6217fc4d5fef0b2b9f75dbf5154"}, - {file = "watchfiles-0.19.0-cp37-abi3-win_amd64.whl", hash = "sha256:945be0baa3e2440151eb3718fd8846751e8b51d8de7b884c90b17d271d34cae8"}, - {file = "watchfiles-0.19.0-cp37-abi3-win_arm64.whl", hash = "sha256:0089c6dc24d436b373c3c57657bf4f9a453b13767150d17284fc6162b2791911"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cae3dde0b4b2078f31527acff6f486e23abed307ba4d3932466ba7cdd5ecec79"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f3920b1285a7d3ce898e303d84791b7bf40d57b7695ad549dc04e6a44c9f120"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9afd0d69429172c796164fd7fe8e821ade9be983f51c659a38da3faaaaac44dc"}, - {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68dce92b29575dda0f8d30c11742a8e2b9b8ec768ae414b54f7453f27bdf9545"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5569fc7f967429d4bc87e355cdfdcee6aabe4b620801e2cf5805ea245c06097c"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5471582658ea56fca122c0f0d0116a36807c63fefd6fdc92c71ca9a4491b6b48"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b538014a87f94d92f98f34d3e6d2635478e6be6423a9ea53e4dd96210065e193"}, - {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b44221764955b1e703f012c74015306fb7e79a00c15370785f309b1ed9aa8d"}, - {file = "watchfiles-0.19.0.tar.gz", hash = "sha256:d9b073073e048081e502b6c6b0b88714c026a1a4c890569238d04aca5f9ca74b"}, + {file = "watchfiles-0.20.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9"}, + {file = "watchfiles-0.20.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458"}, + {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490"}, + {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa"}, + {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38"}, + {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0"}, + {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95"}, + {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf"}, + {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db"}, + {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164"}, + {file = "watchfiles-0.20.0-cp37-abi3-win32.whl", hash = "sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5"}, + {file = "watchfiles-0.20.0-cp37-abi3-win_amd64.whl", hash = "sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3"}, + {file = "watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c"}, + {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d97db179f7566dcf145c5179ddb2ae2a4450e3a634eb864b09ea04e68c252e8e"}, + {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:835df2da7a5df5464c4a23b2d963e1a9d35afa422c83bf4ff4380b3114603644"}, + {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608cd94a8767f49521901aff9ae0c92cc8f5a24d528db7d6b0295290f9d41193"}, + {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d1de8218874925bce7bb2ae9657efc504411528930d7a83f98b1749864f2ef"}, + {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:13f995d5152a8ba4ed7c2bbbaeee4e11a5944defc7cacd0ccb4dcbdcfd78029a"}, + {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b5c8d3be7b502f8c43a33c63166ada8828dbb0c6d49c8f9ce990a96de2f5a49"}, + {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e43af4464daa08723c04b43cf978ab86cc55c684c16172622bdac64b34e36af0"}, + {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d9e1f75c4f86c93d73b5bd1ebe667558357548f11b4f8af4e0e272f79413ce"}, + {file = "watchfiles-0.20.0.tar.gz", hash = "sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019"}, ] [package.dependencies] @@ -5850,32 +3892,18 @@ anyio = ">=3.0.0" [[package]] name = "weaviate-client" -<<<<<<< HEAD -version = "3.22.1" +version = "3.23.2" description = "A python native Weaviate client" optional = false python-versions = ">=3.8" files = [ - {file = "weaviate-client-3.22.1.tar.gz", hash = "sha256:aff61bd3f5d74df20a62328443e3aa9c860d5330fdfb19c4d8ddc44cb604032f"}, - {file = "weaviate_client-3.22.1-py3-none-any.whl", hash = "sha256:01843a4899a227300e570409e77628e9d1b28476313f94943c37aee3f75112e1"}, -======= -version = "3.19.2" -description = "A python native weaviate client" -optional = false -python-versions = ">=3.8" -files = [ - {file = "weaviate-client-3.19.2.tar.gz", hash = "sha256:662cb2a5f6dacc2c9cdf6db2df70e9a3ac9d18b404d0c2ff971d9cb85d84ebed"}, - {file = "weaviate_client-3.19.2-py3-none-any.whl", hash = "sha256:f4bbfb868907089f57fdfb836c4d00cf8a6fc5e296fa08879681ba1d2273cd40"}, ->>>>>>> second-repo/main + {file = "weaviate-client-3.23.2.tar.gz", hash = "sha256:1c8c94df032dd2fa5a4ea615fc69ccb983ffad5cc02974f78c793839e61ac150"}, + {file = "weaviate_client-3.23.2-py3-none-any.whl", hash = "sha256:88ffc38cca07806d64726cc74bc194c7da50b222aa4e2cd129f4c1f5e53e9b61"}, ] [package.dependencies] authlib = ">=1.1.0" -<<<<<<< HEAD requests = ">=2.28.0,<=2.31.0" -======= -requests = ">=2.28.0,<2.29.0" ->>>>>>> second-repo/main tqdm = ">=4.59.0,<5.0.0" validators = ">=0.18.2,<=0.21.0" @@ -5973,30 +4001,17 @@ files = [ [[package]] name = "wheel" -<<<<<<< HEAD version = "0.41.2" -======= -version = "0.40.0" ->>>>>>> second-repo/main description = "A built-package format for Python" optional = false python-versions = ">=3.7" files = [ -<<<<<<< HEAD {file = "wheel-0.41.2-py3-none-any.whl", hash = "sha256:75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8"}, {file = "wheel-0.41.2.tar.gz", hash = "sha256:0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985"}, ] [package.extras] test = ["pytest (>=6.0.0)", "setuptools (>=65)"] -======= - {file = "wheel-0.40.0-py3-none-any.whl", hash = "sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247"}, - {file = "wheel-0.40.0.tar.gz", hash = "sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873"}, -] - -[package.extras] -test = ["pytest (>=6.0.0)"] ->>>>>>> second-repo/main [[package]] name = "win32-setctime" @@ -6112,7 +4127,6 @@ multidict = ">=4.0" [[package]] name = "zipp" -<<<<<<< HEAD version = "3.16.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false @@ -6125,20 +4139,6 @@ files = [ [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] -======= -version = "3.15.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.7" -files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] ->>>>>>> second-repo/main [[package]] name = "zstandard" @@ -6204,8 +4204,4 @@ postgresql = ["psycopg2cffi"] [metadata] lock-version = "2.0" python-versions = "^3.10" -<<<<<<< HEAD -content-hash = "9213703fd449560f1d0a019f0204e5236353f6556b5da1dcb76d9f6de9f73ad0" -======= -content-hash = "9140339a3000bae678247d4ec1c314ed4842957d435a7ae28cc928c7678f84c0" ->>>>>>> second-repo/main +content-hash = "4fa7c1db5527fdc9e0e6e43f800c8a0af0d3ed6242ca80f08b689ad138fc4ec0" diff --git a/pyproject.toml b/pyproject.toml index 7465053a8..0a3575360 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ psycopg2cffi = {version = "^2.9.0", optional = true} loguru = "^0.7.0" elasticsearch = "8.8.2" pykx="^1.6.3" -kdbai_client = { path = "../kdbai-python-client" } +kdbai_client = { path = "/Users/alexg/vector/kdbai-python-client" } [tool.poetry.scripts] start = "server.main:start" From d8b1a4cdfbfe7958576db8412b1574c970f9b100 Mon Sep 17 00:00:00 2001 From: agiannakoulopoulos Date: Thu, 7 Sep 2023 18:55:53 +0100 Subject: [PATCH 14/28] Fix delete functionality --- datastore/providers/kdbai_datastore.py | 34 +++++++++----------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index 9bb61c376..e8f3910fe 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -155,29 +155,17 @@ async def delete( """ Removes vectors by ids, filter, or everything from the index. """ - # Delete all vectors from the index if delete_all is True - if delete_all: - try: - logger.info(f"Deleting all vectors from index") - for id in self._session.list(): - self._session.table(id).drop() - logger.info(f"Dropped {id}") + # Delete all vectors and assosiated index + + try: + if delete_all: + self._table.drop() logger.info(f"Deleted all vectors successfully") return True - - except Exception as e: - logger.error(f"Error deleting all vectors: {e}") - raise e - - if ids is not None and len(ids) > 0: - try: - logger.info(f"Deleting vectors with ids {ids}") - for id in ids: - self._session.table(id).drop() - logger.info(f"Dropped {id}") - logger.info(f"Deleted vectors with ids successfully") - except Exception as e: - logger.error(f"Error deleting vectors with ids: {e}") - raise e + else: + logger.error("Functionality is not implemented yet") + + except Exception as e: + logger.error("Failed to delete records, error: {}".format(e)) + return [] - return True \ No newline at end of file From c679c9f0617f68d3801001a8e8aad2645be30366 Mon Sep 17 00:00:00 2001 From: agiannakoulopoulos Date: Thu, 7 Sep 2023 18:57:20 +0100 Subject: [PATCH 15/28] update notebook --- examples/providers/kdbai/ChatGPT_QA_Demo.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index 2d5fd4111..24f6afacf 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -568,7 +568,7 @@ " },\n", " \n", " json = {\n", - " \"ids\": ['documents']\n", + " \"delete_all\": True\n", " }\n", "\n", ")" From 1b242141cb5498cf77064f9c3446bcf545efe2d6 Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Fri, 8 Sep 2023 16:17:41 +0200 Subject: [PATCH 16/28] Update kdbai-client python dependency. --- poetry.lock | 489 ++++++++++++++++++++++++++++++------------------- pyproject.toml | 4 +- 2 files changed, 301 insertions(+), 192 deletions(-) diff --git a/poetry.lock b/poetry.lock index eb59d6731..17ebbe223 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -213,13 +213,13 @@ files = [ [[package]] name = "azure-core" -version = "1.29.3" +version = "1.29.4" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "azure-core-1.29.3.tar.gz", hash = "sha256:c92700af982e71c8c73de9f4c20da8b3f03ce2c22d13066e4d416b4629c87903"}, - {file = "azure_core-1.29.3-py3-none-any.whl", hash = "sha256:f8b2910f92b66293d93bd00564924ad20ad48f4a1e150577cf18d1e7d4f9263c"}, + {file = "azure-core-1.29.4.tar.gz", hash = "sha256:500b3aa9bf2e90c5ccc88bb105d056114ca0ce7d0ce73afb8bc4d714b2fc7568"}, + {file = "azure_core-1.29.4-py3-none-any.whl", hash = "sha256:b03261bcba22c0b9290faf9999cedd23e849ed2577feee90515694cea6bc74bf"}, ] [package.dependencies] @@ -771,18 +771,22 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "dataclasses-json" -version = "0.6.0" -description = "Easily serialize dataclasses to and from JSON." +version = "0.5.9" +description = "Easily serialize dataclasses to and from JSON" optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.6" files = [ - {file = "dataclasses_json-0.6.0-py3-none-any.whl", hash = "sha256:77cbc80041007c27db90abad79eeed9ea00d4627324b1208266379a6ebdc81e4"}, - {file = "dataclasses_json-0.6.0.tar.gz", hash = "sha256:5bcd5c1d946a69ef94d8cbb726d87af1256f7ba0898809c7695d299ab9b45122"}, + {file = "dataclasses-json-0.5.9.tar.gz", hash = "sha256:e9ac87b73edc0141aafbce02b44e93553c3123ad574958f0fe52a534b6707e8e"}, + {file = "dataclasses_json-0.5.9-py3-none-any.whl", hash = "sha256:1280542631df1c375b7bc92e5b86d39e06c44760d7e3571a537b3b8acabf2f0c"}, ] [package.dependencies] -marshmallow = ">=3.18.0,<4.0.0" -typing-inspect = ">=0.4.0,<1" +marshmallow = ">=3.3.0,<4.0.0" +marshmallow-enum = ">=1.5.1,<2.0.0" +typing-inspect = ">=0.4.0" + +[package.extras] +dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=7.2.0)", "setuptools", "simplejson", "twine", "types-dataclasses", "wheel"] [[package]] name = "deprecation" @@ -1170,6 +1174,7 @@ files = [ {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"}, {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, @@ -1178,6 +1183,7 @@ files = [ {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, @@ -1207,6 +1213,7 @@ files = [ {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, @@ -1215,6 +1222,7 @@ files = [ {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"}, {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, @@ -1233,117 +1241,117 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.57.0" +version = "1.58.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.57.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:092fa155b945015754bdf988be47793c377b52b88d546e45c6a9f9579ac7f7b6"}, - {file = "grpcio-1.57.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2f7349786da979a94690cc5c2b804cab4e8774a3cf59be40d037c4342c906649"}, - {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:82640e57fb86ea1d71ea9ab54f7e942502cf98a429a200b2e743d8672171734f"}, - {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40b72effd4c789de94ce1be2b5f88d7b9b5f7379fe9645f198854112a6567d9a"}, - {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f708a6a17868ad8bf586598bee69abded4996b18adf26fd2d91191383b79019"}, - {file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:60fe15288a0a65d5c1cb5b4a62b1850d07336e3ba728257a810317be14f0c527"}, - {file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6907b1cf8bb29b058081d2aad677b15757a44ef2d4d8d9130271d2ad5e33efca"}, - {file = "grpcio-1.57.0-cp310-cp310-win32.whl", hash = "sha256:57b183e8b252825c4dd29114d6c13559be95387aafc10a7be645462a0fc98bbb"}, - {file = "grpcio-1.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:7b400807fa749a9eb286e2cd893e501b110b4d356a218426cb9c825a0474ca56"}, - {file = "grpcio-1.57.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:c6ebecfb7a31385393203eb04ed8b6a08f5002f53df3d59e5e795edb80999652"}, - {file = "grpcio-1.57.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:00258cbe3f5188629828363ae8ff78477ce976a6f63fb2bb5e90088396faa82e"}, - {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:23e7d8849a0e58b806253fd206ac105b328171e01b8f18c7d5922274958cc87e"}, - {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5371bcd861e679d63b8274f73ac281751d34bd54eccdbfcd6aa00e692a82cd7b"}, - {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aed90d93b731929e742967e236f842a4a2174dc5db077c8f9ad2c5996f89f63e"}, - {file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe752639919aad9ffb0dee0d87f29a6467d1ef764f13c4644d212a9a853a078d"}, - {file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fada6b07ec4f0befe05218181f4b85176f11d531911b64c715d1875c4736d73a"}, - {file = "grpcio-1.57.0-cp311-cp311-win32.whl", hash = "sha256:bb396952cfa7ad2f01061fbc7dc1ad91dd9d69243bcb8110cf4e36924785a0fe"}, - {file = "grpcio-1.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:e503cb45ed12b924b5b988ba9576dc9949b2f5283b8e33b21dcb6be74a7c58d0"}, - {file = "grpcio-1.57.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:fd173b4cf02b20f60860dc2ffe30115c18972d7d6d2d69df97ac38dee03be5bf"}, - {file = "grpcio-1.57.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:d7f8df114d6b4cf5a916b98389aeaf1e3132035420a88beea4e3d977e5f267a5"}, - {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:76c44efa4ede1f42a9d5b2fed1fe9377e73a109bef8675fb0728eb80b0b8e8f2"}, - {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4faea2cfdf762a664ab90589b66f416274887641ae17817de510b8178356bf73"}, - {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c60b83c43faeb6d0a9831f0351d7787a0753f5087cc6fa218d78fdf38e5acef0"}, - {file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b363bbb5253e5f9c23d8a0a034dfdf1b7c9e7f12e602fc788c435171e96daccc"}, - {file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f1fb0fd4a1e9b11ac21c30c169d169ef434c6e9344ee0ab27cfa6f605f6387b2"}, - {file = "grpcio-1.57.0-cp37-cp37m-win_amd64.whl", hash = "sha256:34950353539e7d93f61c6796a007c705d663f3be41166358e3d88c45760c7d98"}, - {file = "grpcio-1.57.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:871f9999e0211f9551f368612460442a5436d9444606184652117d6a688c9f51"}, - {file = "grpcio-1.57.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:a8a8e560e8dbbdf29288872e91efd22af71e88b0e5736b0daf7773c1fecd99f0"}, - {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2313b124e475aa9017a9844bdc5eafb2d5abdda9d456af16fc4535408c7d6da6"}, - {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4098b6b638d9e0ca839a81656a2fd4bc26c9486ea707e8b1437d6f9d61c3941"}, - {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e5b58e32ae14658085c16986d11e99abd002ddbf51c8daae8a0671fffb3467f"}, - {file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0f80bf37f09e1caba6a8063e56e2b87fa335add314cf2b78ebf7cb45aa7e3d06"}, - {file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5b7a4ce8f862fe32b2a10b57752cf3169f5fe2915acfe7e6a1e155db3da99e79"}, - {file = "grpcio-1.57.0-cp38-cp38-win32.whl", hash = "sha256:9338bacf172e942e62e5889b6364e56657fbf8ac68062e8b25c48843e7b202bb"}, - {file = "grpcio-1.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:e1cb52fa2d67d7f7fab310b600f22ce1ff04d562d46e9e0ac3e3403c2bb4cc16"}, - {file = "grpcio-1.57.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fee387d2fab144e8a34e0e9c5ca0f45c9376b99de45628265cfa9886b1dbe62b"}, - {file = "grpcio-1.57.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b53333627283e7241fcc217323f225c37783b5f0472316edcaa4479a213abfa6"}, - {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f19ac6ac0a256cf77d3cc926ef0b4e64a9725cc612f97228cd5dc4bd9dbab03b"}, - {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fdf04e402f12e1de8074458549337febb3b45f21076cc02ef4ff786aff687e"}, - {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5613a2fecc82f95d6c51d15b9a72705553aa0d7c932fad7aed7afb51dc982ee5"}, - {file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b670c2faa92124b7397b42303e4d8eb64a4cd0b7a77e35a9e865a55d61c57ef9"}, - {file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a635589201b18510ff988161b7b573f50c6a48fae9cb567657920ca82022b37"}, - {file = "grpcio-1.57.0-cp39-cp39-win32.whl", hash = "sha256:d78d8b86fcdfa1e4c21f8896614b6cc7ee01a2a758ec0c4382d662f2a62cf766"}, - {file = "grpcio-1.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:20ec6fc4ad47d1b6e12deec5045ec3cd5402d9a1597f738263e98f490fe07056"}, - {file = "grpcio-1.57.0.tar.gz", hash = "sha256:4b089f7ad1eb00a104078bab8015b0ed0ebcb3b589e527ab009c53893fd4e613"}, + {file = "grpcio-1.58.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:3e6bebf1dfdbeb22afd95650e4f019219fef3ab86d3fca8ebade52e4bc39389a"}, + {file = "grpcio-1.58.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:cde11577d5b6fd73a00e6bfa3cf5f428f3f33c2d2878982369b5372bbc4acc60"}, + {file = "grpcio-1.58.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a2d67ff99e70e86b2be46c1017ae40b4840d09467d5455b2708de6d4c127e143"}, + {file = "grpcio-1.58.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ed979b273a81de36fc9c6716d9fb09dd3443efa18dcc8652501df11da9583e9"}, + {file = "grpcio-1.58.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:458899d2ebd55d5ca2350fd3826dfd8fcb11fe0f79828ae75e2b1e6051d50a29"}, + {file = "grpcio-1.58.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc7ffef430b80345729ff0a6825e9d96ac87efe39216e87ac58c6c4ef400de93"}, + {file = "grpcio-1.58.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5b23d75e5173faa3d1296a7bedffb25afd2fddb607ef292dfc651490c7b53c3d"}, + {file = "grpcio-1.58.0-cp310-cp310-win32.whl", hash = "sha256:fad9295fe02455d4f158ad72c90ef8b4bcaadfdb5efb5795f7ab0786ad67dd58"}, + {file = "grpcio-1.58.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc325fed4d074367bebd465a20763586e5e1ed5b943e9d8bc7c162b1f44fd602"}, + {file = "grpcio-1.58.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:652978551af02373a5a313e07bfef368f406b5929cf2d50fa7e4027f913dbdb4"}, + {file = "grpcio-1.58.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:9f13a171281ebb4d7b1ba9f06574bce2455dcd3f2f6d1fbe0fd0d84615c74045"}, + {file = "grpcio-1.58.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8774219e21b05f750eef8adc416e9431cf31b98f6ce9def288e4cea1548cbd22"}, + {file = "grpcio-1.58.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09206106848462763f7f273ca93d2d2d4d26cab475089e0de830bb76be04e9e8"}, + {file = "grpcio-1.58.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62831d5e251dd7561d9d9e83a0b8655084b2a1f8ea91e4bd6b3cedfefd32c9d2"}, + {file = "grpcio-1.58.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:212f38c6a156862098f6bdc9a79bf850760a751d259d8f8f249fc6d645105855"}, + {file = "grpcio-1.58.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4b12754af201bb993e6e2efd7812085ddaaef21d0a6f0ff128b97de1ef55aa4a"}, + {file = "grpcio-1.58.0-cp311-cp311-win32.whl", hash = "sha256:3886b4d56bd4afeac518dbc05933926198aa967a7d1d237a318e6fbc47141577"}, + {file = "grpcio-1.58.0-cp311-cp311-win_amd64.whl", hash = "sha256:002f228d197fea12797a14e152447044e14fb4fdb2eb5d6cfa496f29ddbf79ef"}, + {file = "grpcio-1.58.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:b5e8db0aff0a4819946215f156bd722b6f6c8320eb8419567ffc74850c9fd205"}, + {file = "grpcio-1.58.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:201e550b7e2ede113b63e718e7ece93cef5b0fbf3c45e8fe4541a5a4305acd15"}, + {file = "grpcio-1.58.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:d79b660681eb9bc66cc7cbf78d1b1b9e335ee56f6ea1755d34a31108b80bd3c8"}, + {file = "grpcio-1.58.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ef8d4a76d2c7d8065aba829f8d0bc0055495c998dce1964ca5b302d02514fb3"}, + {file = "grpcio-1.58.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cba491c638c76d3dc6c191d9c75041ca5b8f5c6de4b8327ecdcab527f130bb4"}, + {file = "grpcio-1.58.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6801ff6652ecd2aae08ef994a3e49ff53de29e69e9cd0fd604a79ae4e545a95c"}, + {file = "grpcio-1.58.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:24edec346e69e672daf12b2c88e95c6f737f3792d08866101d8c5f34370c54fd"}, + {file = "grpcio-1.58.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7e473a7abad9af48e3ab5f3b5d237d18208024d28ead65a459bd720401bd2f8f"}, + {file = "grpcio-1.58.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:4891bbb4bba58acd1d620759b3be11245bfe715eb67a4864c8937b855b7ed7fa"}, + {file = "grpcio-1.58.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:e9f995a8a421405958ff30599b4d0eec244f28edc760de82f0412c71c61763d2"}, + {file = "grpcio-1.58.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2f85f87e2f087d9f632c085b37440a3169fda9cdde80cb84057c2fc292f8cbdf"}, + {file = "grpcio-1.58.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb6b92036ff312d5b4182fa72e8735d17aceca74d0d908a7f08e375456f03e07"}, + {file = "grpcio-1.58.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d81c2b2b24c32139dd2536972f1060678c6b9fbd106842a9fcdecf07b233eccd"}, + {file = "grpcio-1.58.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fbcecb6aedd5c1891db1d70efbfbdc126c986645b5dd616a045c07d6bd2dfa86"}, + {file = "grpcio-1.58.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92ae871a902cf19833328bd6498ec007b265aabf2fda845ab5bd10abcaf4c8c6"}, + {file = "grpcio-1.58.0-cp38-cp38-win32.whl", hash = "sha256:dc72e04620d49d3007771c0e0348deb23ca341c0245d610605dddb4ac65a37cb"}, + {file = "grpcio-1.58.0-cp38-cp38-win_amd64.whl", hash = "sha256:1c1c5238c6072470c7f1614bf7c774ffde6b346a100521de9ce791d1e4453afe"}, + {file = "grpcio-1.58.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fe643af248442221db027da43ed43e53b73e11f40c9043738de9a2b4b6ca7697"}, + {file = "grpcio-1.58.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:128eb1f8e70676d05b1b0c8e6600320fc222b3f8c985a92224248b1367122188"}, + {file = "grpcio-1.58.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:039003a5e0ae7d41c86c768ef8b3ee2c558aa0a23cf04bf3c23567f37befa092"}, + {file = "grpcio-1.58.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f061722cad3f9aabb3fbb27f3484ec9d4667b7328d1a7800c3c691a98f16bb0"}, + {file = "grpcio-1.58.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0af11938acf8cd4cf815c46156bcde36fa5850518120920d52620cc3ec1830"}, + {file = "grpcio-1.58.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d4cef77ad2fed42b1ba9143465856d7e737279854e444925d5ba45fc1f3ba727"}, + {file = "grpcio-1.58.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24765a627eb4d9288ace32d5104161c3654128fe27f2808ecd6e9b0cfa7fc8b9"}, + {file = "grpcio-1.58.0-cp39-cp39-win32.whl", hash = "sha256:f0241f7eb0d2303a545136c59bc565a35c4fc3b924ccbd69cb482f4828d6f31c"}, + {file = "grpcio-1.58.0-cp39-cp39-win_amd64.whl", hash = "sha256:dcfba7befe3a55dab6fe1eb7fc9359dc0c7f7272b30a70ae0af5d5b063842f28"}, + {file = "grpcio-1.58.0.tar.gz", hash = "sha256:532410c51ccd851b706d1fbc00a87be0f5312bd6f8e5dbf89d4e99c7f79d7499"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.57.0)"] +protobuf = ["grpcio-tools (>=1.58.0)"] [[package]] name = "grpcio-tools" -version = "1.57.0" +version = "1.58.0" description = "Protobuf code generator for gRPC" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-tools-1.57.0.tar.gz", hash = "sha256:2f16130d869ce27ecd623194547b649dd657333ec7e8644cc571c645781a9b85"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:4fb8a8468031f858381a576078924af364a08833d8f8f3237018252c4573a802"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:35bf0dad8a3562043345236c26d0053a856fb06c04d7da652f2ded914e508ae7"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:ec9aab2fb6783c7fc54bc28f58eb75f1ca77594e6b0fd5e5e7a8114a95169fe0"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf5fc0a1c23f8ea34b408b72fb0e90eec0f404ad4dba98e8f6da3c9ce34e2ed"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26e69d08a515554e0cfe1ec4d31568836f4b17f0ff82294f957f629388629eb9"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c39a3656576b6fdaaf28abe0467f7a7231df4230c1bee132322dbc3209419e7f"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f64f8ab22d27d4a5693310748d35a696061c3b5c7b8c4fb4ab3b4bc1068b6b56"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-win32.whl", hash = "sha256:d2a134756f4db34759a5cc7f7e43f7eb87540b68d1cca62925593c6fb93924f7"}, - {file = "grpcio_tools-1.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a3d60fb8d46ede26c1907c146561b3a9caa20a7aff961bc661ef8226f85a2e9"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:aac98ecad8f7bd4301855669d42a5d97ef7bb34bec2b1e74c7a0641d47e313cf"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:cdd020cb68b51462983b7c2dfbc3eb6ede032b8bf438d4554df0c3f08ce35c76"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:f54081b08419a39221cd646363b5708857c696b3ad4784f1dcf310891e33a5f7"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed85a0291fff45b67f2557fe7f117d3bc7af8b54b8619d27bf374b5c8b7e3ca2"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e868cd6feb3ef07d4b35be104fe1fd0657db05259ff8f8ec5e08f4f89ca1191d"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:dfb6f6120587b8e228a3cae5ee4985b5bdc18501bad05c49df61965dfc9d70a9"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4a7ad7f328e28fc97c356d0f10fb10d8b5151bb65aa7cf14bf8084513f0b7306"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-win32.whl", hash = "sha256:9867f2817b1a0c93c523f89ac6c9d8625548af4620a7ce438bf5a76e23327284"}, - {file = "grpcio_tools-1.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:1f9e917a9f18087f6c14b4d4508fb94fca5c2f96852363a89232fb9b2124ac1f"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:9f2aefa8a37bd2c4db1a3f1aca11377e2766214520fb70e67071f4ff8d8b0fa5"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:850cbda0ec5d24c39e7215ede410276040692ca45d105fbbeada407fa03f0ac0"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6fa52972c9647876ea35f6dc2b51002a74ed900ec7894586cbb2fe76f64f99de"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0eea89d7542719594e50e2283f51a072978b953e8b3e9fd7c59a2c762d4c1"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3da5240211252fc70a6451fe00c143e2ab2f7bfc2445695ad2ed056b8e48d96"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a0256f8786ac9e4db618a1aa492bb3472569a0946fd3ee862ffe23196323da55"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c026bdf5c1366ce88b7bbe2d8207374d675afd3fd911f60752103de3da4a41d2"}, - {file = "grpcio_tools-1.57.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9053c2f655589545be08b9d6a673e92970173a4bf11a4b9f18cd6e9af626b587"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:81ec4dbb696e095057b2528d11a8da04be6bbe2b967fa07d4ea9ba6354338cbf"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:495e2946406963e0b9f063f76d5af0f2a19517dac2b367b5b044432ac9194296"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:7b46fc6aa8eb7edd18cafcd21fd98703cb6c09e46b507de335fca7f0161dfccb"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb81ff861692111fa81bd85f64584e624cb4013bd66fbce8a209b8893f5ce398"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a42dc220eb5305f470855c9284f4c8e85ae59d6d742cd07946b0cbe5e9ca186"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90d10d9038ba46a595a223a34f136c9230e3d6d7abc2433dbf0e1c31939d3a8b"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5bc3e6d338aefb052e19cedabe00452be46d0c10a4ed29ee77abb00402e438fe"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-win32.whl", hash = "sha256:34b36217b17b5bea674a414229913e1fd80ede328be51e1b531fcc62abd393b0"}, - {file = "grpcio_tools-1.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbde4004a0688400036342ff73e3706e8940483e2871547b1354d59e93a38277"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:784574709b9690dc28696617ea69352e2132352fdfc9bc89afa8e39f99ae538e"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:85ac4e62eb44428cde025fd9ab7554002315fc7880f791c553fc5a0015cc9931"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:dc771d4db5701f280957bbcee91745e0686d00ed1c6aa7e05ba30a58b02d70a1"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3ac06703c412f8167a9062eaf6099409967e33bf98fa5b02be4b4689b6bdf39"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02d78c034109f46032c7217260066d49d41e6bcaf588fa28fa40fe2f83445347"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2db25f15ed44327f2e02d0c4fe741ac966f9500e407047d8a7c7fccf2df65616"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b417c97936d94874a3ce7ed8deab910f2233e3612134507cfee4af8735c38a6"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-win32.whl", hash = "sha256:f717cce5093e6b6049d9ea6d12fdf3658efdb1a80772f7737db1f8510b876df6"}, - {file = "grpcio_tools-1.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:1c0e8a1a32973a5d59fbcc19232f925e5c48116e9411f788033a31c5ca5130b4"}, + {file = "grpcio-tools-1.58.0.tar.gz", hash = "sha256:6f4d80ceb591e31ca4dceec747dbe56132e1392a0a9bb1c8fe001d1b5cac898a"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:60c874908f3b40f32f1bb0221f7b3ab65ecb53a4d0a9f0a394f031f1b292c177"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:1852e798f31e5437ca7b37abc910e028b34732fb19364862cedb87b1dab66fad"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:149fb48f53cb691a6328f68bed8e4036c730f7106b7f98e92c2c0403f0b9e93c"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba3d383e5ca93826038b70f326fce8e8d12dd9b2f64d363a3d612f7475f12dd2"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6997511e9d2979f7a2389479682dbb06823f21a904e8fb0a5c6baaf1b4b4a863"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8de0b701da479643f71fad71fe66885cddd89441ae16e2c724939b47742dc72e"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43cc23908b63fcaefe690b10f68a2d8652c994b5b36ab77d2271d9608c895320"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-win32.whl", hash = "sha256:2c2221123d010dc6231799e63a37f2f4786bf614ef65b23009c387cd20d8b193"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-win_amd64.whl", hash = "sha256:df2788736bdf58abe7b0e4d6b1ff806f7686c98c5ad900da312252e3322d91c4"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:b6ea5578712cdb29b0ff60bfc6405bf0e8d681b9c71d106dd1cda54fe7fe4e55"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:c29880f491581c83181c0a84a4d11402af2b13166a5266f64e246adf1da7aa66"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:32d51e933c3565414dd0835f930bb28a1cdeba435d9d2c87fa3cf8b1d284db3c"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ad9d77f25514584b1ddc981d70c9e50dfcfc388aa5ba943eee67520c5267ed9"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4882382631e6352819059278a5c878ce0b067008dd490911d16d5616e8a36d85"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d84091a189d848d94645b7c48b61734c12ec03b0d46e5fc0049343a26989ac5c"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:85ac28a9621e9b92a3fc416288c4ce45542db0b4c31b3e23031dd8e0a0ec5590"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-win32.whl", hash = "sha256:7371d8ea80234b29affec145e25569523f549520ed7e53b2aa92bed412cdecfd"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-win_amd64.whl", hash = "sha256:6997df6e7c5cf4d3ddc764240c1ff6a04b45d70ec28913b38fbc6396ef743e12"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:ac65b8d6e3acaf88b815edf9af88ff844b6600ff3d2591c05ba4f655b45d5fb4"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:88e8191d0dd789bebf42533808728f5ce75d2c51e2a72bdf20abe5b5e3fbec42"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:a3dbece2a121761499a659b799979d4b738586d1065439053de553773eee11ca"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1086fe240c4c879b9721952b47d46996deb283c2d9355a8dc24a804811aacf70"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7ae3dca059d5b358dd03fb63277428fa7d771605d4074a019138dd38d70719a"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3f8904ac7fc3da2e874f00b3a986e8b7e004f499344a8e7eb213c26dfb025041"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:aadbd8393ae332e49731adb31e741f2e689989150569b7acc939f5ea43124e2d"}, + {file = "grpcio_tools-1.58.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1cb6e24194786687d4f23c64de1f0ce553af51de22746911bc37340f85f9783e"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:6ec43909095c630df3e479e77469bdad367067431f4af602f6ccb978a3b78afd"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:4be49ed320b0ebcbc21d19ef555fbf229c1c452105522b728e1171ee2052078e"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:28eefebddec3d3adf19baca78f8b82a2287d358e1b1575ae018cdca8eacc6269"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ef8c696e9d78676cc3f583a92bbbf2c84e94e350f7ad22f150a52559f4599d1"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aeb5949e46558d21c51fd3ec3eeecc59c94dbca76c67c0a80d3da6b7437930c"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f7144aad9396d35fb1b80429600a970b559c2ad4d07020eeb180fe83cea2bee"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4ee26e9253a721fff355737649678535f76cf5d642aa3ac0cd937832559b90af"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-win32.whl", hash = "sha256:343f572312039059a8797d6e29a7fc62196e73131ab01755660a9d48202267c1"}, + {file = "grpcio_tools-1.58.0-cp38-cp38-win_amd64.whl", hash = "sha256:cd7acfbb43b7338a78cf4a67528d05530d574d92b7c829d185b78dfc451d158f"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:46628247fbce86d18232eead24bd22ed0826c79f3fe2fc2fbdbde45971361049"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:51587842a54e025a3d0d37afcf4ef2b7ac1def9a5d17448665cb424b53d6c287"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:a062ae3072a2a39a3c057f4d68b57b021f1dd2956cd09aab39709f6af494e1de"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec3c93a08df11c80ef1c29a616bcbb0d83dbc6ea41b48306fcacc720416dfa7"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b63f823ac991ff77104da614d2a2485a59d37d57830eb2e387a6e2a3edc7fa2b"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:579c11a9f198847ed48dbc4f211c67fe96a73320b87c81f01b044b72e24a7d77"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2fc1dd8049d417a5034d944c9df05cee76f855b3e431627ab4292e7c01c47"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-win32.whl", hash = "sha256:453023120114c35d3d9d6717ea0820e5d5c140f51f9d0b621de4397ff854471b"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-win_amd64.whl", hash = "sha256:b6c896f1df99c35cf062d4803c15663ff00a33ff09add28baa6e475cf6b5e258"}, ] [package.dependencies] -grpcio = ">=1.57.0" +grpcio = ">=1.58.0" protobuf = ">=4.21.6,<5.0dev" setuptools = "*" @@ -1647,12 +1655,13 @@ trio = ["async_generator", "trio"] [[package]] name = "kdbai-client" -version = "0.0.0" +version = "0.0.0.dev5" description = "KDB.AI Client for Python" optional = false -python-versions = "^3.8" -files = [] -develop = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "kdbai_client-0.0.0.dev5-py3-none-any.whl", hash = "sha256:1895176f2d9de4a38e65a3b4d4eedfc993a0ffd30b927f27aa1f344593d6e176"}, +] [package.dependencies] pandas = ">=1.5.0" @@ -1662,10 +1671,6 @@ pykx = ">=1.6.0" lint = ["mypy", "mypy-gitlab-code-quality"] test = ["pytest (>=7.3.2,<8.0.0)", "pytest-cov (>=4.0.0,<5.0.0)", "pytest-mock"] -[package.source] -type = "directory" -url = "../vector/kdbai-python-client" - [[package]] name = "keyring" version = "24.2.0" @@ -1691,25 +1696,56 @@ testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", [[package]] name = "langchain" -version = "0.0.70" +version = "0.0.284" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain-0.0.70-py3-none-any.whl", hash = "sha256:55352197c65072d13058715b75a6e9f966d23234086323cddacc25e309ff3bbd"}, - {file = "langchain-0.0.70.tar.gz", hash = "sha256:53c197248a3f789cc424aa812233ebe2ecadfef6a00c78a2a805f18c723fb475"}, + {file = "langchain-0.0.284-py3-none-any.whl", hash = "sha256:e6c759c2eb49d0894ce654f40936d9818f14b489f07e2349466d3a3113322c3c"}, + {file = "langchain-0.0.284.tar.gz", hash = "sha256:2e0748448fa00d2825411ab840006eaab8806848ee20c09cdc7e913c19a9f750"}, ] [package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} +dataclasses-json = ">=0.5.7,<0.6.0" +langsmith = ">=0.0.21,<0.1.0" +numexpr = ">=2.8.4,<3.0.0" numpy = ">=1,<2" -pydantic = ">=1,<2" -PyYAML = ">=6,<7" +pydantic = ">=1,<3" +PyYAML = ">=5.3" requests = ">=2,<3" -SQLAlchemy = ">=1,<2" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" [package.extras] -all = ["beautifulsoup4 (>=4,<5)", "elasticsearch (>=8,<9)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "jinja2 (>=3,<4)", "manifest-ml (>=0.0.1,<0.0.2)", "nltk (>=3,<4)", "pinecone-client (>=2,<3)", "qdrant-client (>=0.11.7,<0.12.0)", "redis (>=4,<5)", "spacy (>=3,<4)", "tiktoken (>=0,<1)", "torch (>=1,<2)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] -llms = ["manifest-ml (>=0.0.1,<0.0.2)", "torch (>=1,<2)", "transformers (>=4,<5)"] +all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "amadeus (>=8.1.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.9,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clarifai (>=9.1.0)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=4,<5)", "deeplake (>=3.6.8,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.6,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "libdeeplake (>=0.0.60,<0.0.61)", "librosa (>=0.10.0.post2,<0.11.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "marqo (>=1.2.4,<2.0.0)", "momento (>=1.5.0,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "python-arango (>=7.5.9,<8.0.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.3.1,<2.0.0)", "rdflib (>=6.3.2,<7.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.4.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] +azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b8)", "openai (>=0,<1)"] +clarifai = ["clarifai (>=9.1.0)"] +cohere = ["cohere (>=4,<5)"] +docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] +embeddings = ["sentence-transformers (>=2,<3)"] +extended-testing = ["amazon-textract-caller (<2)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "dashvector (>=1.0.1,<2.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "openai (>=0,<1)", "openapi-schema-pydantic (>=1.2,<2.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tqdm (>=4.48.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +javascript = ["esprima (>=4.0.1,<5.0.0)"] +llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] +openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.4.0)"] +qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] +text-helpers = ["chardet (>=5.1.0,<6.0.0)"] + +[[package]] +name = "langsmith" +version = "0.0.33" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langsmith-0.0.33-py3-none-any.whl", hash = "sha256:cdff11a6272d3cba72c151960c0319b1d36e0770d37f05061d6c31ef1a2404a4"}, + {file = "langsmith-0.0.33.tar.gz", hash = "sha256:c9c640ac238d4cabc8f9744e04346d3dfaf0ca6c9dc37bd2a25b8031eda35dc3"}, +] + +[package.dependencies] +pydantic = ">=1,<3" +requests = ">=2,<3" [[package]] name = "llama-index" @@ -1924,6 +1960,20 @@ docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "s lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] tests = ["pytest", "pytz", "simplejson"] +[[package]] +name = "marshmallow-enum" +version = "1.5.1" +description = "Enum field for Marshmallow" +optional = false +python-versions = "*" +files = [ + {file = "marshmallow-enum-1.5.1.tar.gz", hash = "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58"}, + {file = "marshmallow_enum-1.5.1-py2.py3-none-any.whl", hash = "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"}, +] + +[package.dependencies] +marshmallow = ">=2.0.0" + [[package]] name = "monotonic" version = "1.6" @@ -2094,6 +2144,48 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "numexpr" +version = "2.8.5" +description = "Fast numerical expression evaluator for NumPy" +optional = false +python-versions = ">=3.7" +files = [ + {file = "numexpr-2.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51f3ab160c3847ebcca93cd88f935a7802b54a01ab63fe93152994a64d7a6cf2"}, + {file = "numexpr-2.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:de29c77f674e4eb8f0846525a475cab64008c227c8bc4ba5153ab3f72441cc63"}, + {file = "numexpr-2.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf85ba1327eb87ec82ae7936f13c8850fb969a0ca34f3ba9fa3897c09d5c80d7"}, + {file = "numexpr-2.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c00be69f747f44a631830215cab482f0f77f75af2925695adff57c1cc0f9a68"}, + {file = "numexpr-2.8.5-cp310-cp310-win32.whl", hash = "sha256:c46350dcdb93e32f033eea5a21269514ffcaf501d9abd6036992d37e48a308b0"}, + {file = "numexpr-2.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:894b027438b8ec88dea32a19193716c79f4ff8ddb92302dcc9731b51ba3565a8"}, + {file = "numexpr-2.8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6df184d40d4cf9f21c71f429962f39332f7398147762588c9f3a5c77065d0c06"}, + {file = "numexpr-2.8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:178b85ad373c6903e55d75787d61b92380439b70d94b001cb055a501b0821335"}, + {file = "numexpr-2.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:578fe4008e4d5d6ff01bbeb2d7b7ba1ec658a5cda9c720cd26a9a8325f8ef438"}, + {file = "numexpr-2.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef621b4ee366a5c6a484f6678c9259f5b826569f8bfa0b89ba2306d5055468bb"}, + {file = "numexpr-2.8.5-cp311-cp311-win32.whl", hash = "sha256:dd57ab1a3d3aaa9274aff1cefbf93b8ddacc7973afef5b125905f6bf18fabab0"}, + {file = "numexpr-2.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:783324ba40eb804ecfc9ebae86120a1e339ab112d0ab8a1f0d48a26354d5bf9b"}, + {file = "numexpr-2.8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:183d5430db76826e54465c69db93a3c6ecbf03cda5aa1bb96eaad0147e9b68dc"}, + {file = "numexpr-2.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ce106f92ccea5b07b1d6f2f3c4370f05edf27691dc720a63903484a2137e48"}, + {file = "numexpr-2.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b594dc9e2d6291a0bc5c065e6d9caf3eee743b5663897832e9b17753c002947a"}, + {file = "numexpr-2.8.5-cp37-cp37m-win32.whl", hash = "sha256:62b4faf8e0627673b0210a837792bddd23050ecebc98069ab23eb0633ff1ef5f"}, + {file = "numexpr-2.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:db5c65417d69414f1ab31302ea01d3548303ef31209c38b4849d145be4e1d1ba"}, + {file = "numexpr-2.8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb36ffcfa1606e41aa08d559b4277bcad0e16b83941d1a4fee8d2bd5a34f8e0e"}, + {file = "numexpr-2.8.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:34af2a0e857d02a4bc5758bc037a777d50dacb13bcd57c7905268a3e44994ed6"}, + {file = "numexpr-2.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a8dad2bfaad5a5c34a2e8bbf62b9df1dfab266d345fda1feb20ff4e264b347a"}, + {file = "numexpr-2.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93f5a866cd13a808bc3d3a9c487d94cd02eec408b275ff0aa150f2e8e5191f8"}, + {file = "numexpr-2.8.5-cp38-cp38-win32.whl", hash = "sha256:558390fea6370003ac749ed9d0f38d708aa096f5dcb707ddb6e0ca5a0dd37da1"}, + {file = "numexpr-2.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:55983806815035eb63c5039520688c49536bb7f3cc3fc1d7d64c6a00cf3f353e"}, + {file = "numexpr-2.8.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1510da20e6f5f45333610b1ded44c566e2690c6c437c84f2a212ca09627c7e01"}, + {file = "numexpr-2.8.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e8b5bf7bcb4e8dcd66522d8fc96e1db7278f901cb4fd2e155efbe62a41dde08"}, + {file = "numexpr-2.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ed0e1c1ef5f34381448539f1fe9015906d21c9cfa2797c06194d4207dadb465"}, + {file = "numexpr-2.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aea6ab45c87c0a7041183c08a798f0ad4d7c5eccbce20cfe79ce6f1a45ef3702"}, + {file = "numexpr-2.8.5-cp39-cp39-win32.whl", hash = "sha256:cbfd833ee5fdb0efb862e152aee7e6ccea9c596d5c11d22604c2e6307bff7cad"}, + {file = "numexpr-2.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:283ce8609a7ccbadf91a68f3484558b3e36d27c93c98a41ec205efb0ab43c872"}, + {file = "numexpr-2.8.5.tar.gz", hash = "sha256:45ed41e55a0abcecf3d711481e12a5fb7a904fe99d42bc282a17cc5f8ea510be"}, +] + +[package.dependencies] +numpy = ">=1.13.3" + [[package]] name = "numpy" version = "1.25.2" @@ -2251,8 +2343,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.1" pytz = ">=2020.1" @@ -2467,24 +2559,24 @@ test = ["coverage", "flake8", "freezegun (==0.3.15)", "mock (>=2.0.0)", "pylint" [[package]] name = "protobuf" -version = "4.24.2" +version = "4.24.3" description = "" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.24.2-cp310-abi3-win32.whl", hash = "sha256:58e12d2c1aa428ece2281cef09bbaa6938b083bcda606db3da4e02e991a0d924"}, - {file = "protobuf-4.24.2-cp310-abi3-win_amd64.whl", hash = "sha256:77700b55ba41144fc64828e02afb41901b42497b8217b558e4a001f18a85f2e3"}, - {file = "protobuf-4.24.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:237b9a50bd3b7307d0d834c1b0eb1a6cd47d3f4c2da840802cd03ea288ae8880"}, - {file = "protobuf-4.24.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:25ae91d21e3ce8d874211110c2f7edd6384816fb44e06b2867afe35139e1fd1c"}, - {file = "protobuf-4.24.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:c00c3c7eb9ad3833806e21e86dca448f46035242a680f81c3fe068ff65e79c74"}, - {file = "protobuf-4.24.2-cp37-cp37m-win32.whl", hash = "sha256:4e69965e7e54de4db989289a9b971a099e626f6167a9351e9d112221fc691bc1"}, - {file = "protobuf-4.24.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c5cdd486af081bf752225b26809d2d0a85e575b80a84cde5172a05bbb1990099"}, - {file = "protobuf-4.24.2-cp38-cp38-win32.whl", hash = "sha256:6bd26c1fa9038b26c5c044ee77e0ecb18463e957fefbaeb81a3feb419313a54e"}, - {file = "protobuf-4.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb7aa97c252279da65584af0456f802bd4b2de429eb945bbc9b3d61a42a8cd16"}, - {file = "protobuf-4.24.2-cp39-cp39-win32.whl", hash = "sha256:2b23bd6e06445699b12f525f3e92a916f2dcf45ffba441026357dea7fa46f42b"}, - {file = "protobuf-4.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:839952e759fc40b5d46be319a265cf94920174d88de31657d5622b5d8d6be5cd"}, - {file = "protobuf-4.24.2-py3-none-any.whl", hash = "sha256:3b7b170d3491ceed33f723bbf2d5a260f8a4e23843799a3906f16ef736ef251e"}, - {file = "protobuf-4.24.2.tar.gz", hash = "sha256:7fda70797ddec31ddfa3576cbdcc3ddbb6b3078b737a1a87ab9136af0570cd6e"}, + {file = "protobuf-4.24.3-cp310-abi3-win32.whl", hash = "sha256:20651f11b6adc70c0f29efbe8f4a94a74caf61b6200472a9aea6e19898f9fcf4"}, + {file = "protobuf-4.24.3-cp310-abi3-win_amd64.whl", hash = "sha256:3d42e9e4796a811478c783ef63dc85b5a104b44aaaca85d4864d5b886e4b05e3"}, + {file = "protobuf-4.24.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:6e514e8af0045be2b56e56ae1bb14f43ce7ffa0f68b1c793670ccbe2c4fc7d2b"}, + {file = "protobuf-4.24.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:ba53c2f04798a326774f0e53b9c759eaef4f6a568ea7072ec6629851c8435959"}, + {file = "protobuf-4.24.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:f6ccbcf027761a2978c1406070c3788f6de4a4b2cc20800cc03d52df716ad675"}, + {file = "protobuf-4.24.3-cp37-cp37m-win32.whl", hash = "sha256:1b182c7181a2891e8f7f3a1b5242e4ec54d1f42582485a896e4de81aa17540c2"}, + {file = "protobuf-4.24.3-cp37-cp37m-win_amd64.whl", hash = "sha256:b0271a701e6782880d65a308ba42bc43874dabd1a0a0f41f72d2dac3b57f8e76"}, + {file = "protobuf-4.24.3-cp38-cp38-win32.whl", hash = "sha256:e29d79c913f17a60cf17c626f1041e5288e9885c8579832580209de8b75f2a52"}, + {file = "protobuf-4.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:067f750169bc644da2e1ef18c785e85071b7c296f14ac53e0900e605da588719"}, + {file = "protobuf-4.24.3-cp39-cp39-win32.whl", hash = "sha256:2da777d34b4f4f7613cdf85c70eb9a90b1fbef9d36ae4a0ccfe014b0b07906f1"}, + {file = "protobuf-4.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:f631bb982c5478e0c1c70eab383af74a84be66945ebf5dd6b06fc90079668d0b"}, + {file = "protobuf-4.24.3-py3-none-any.whl", hash = "sha256:f6f8dc65625dadaad0c8545319c2e2f0424fede988368893ca3844261342c11a"}, + {file = "protobuf-4.24.3.tar.gz", hash = "sha256:12e9ad2ec079b833176d2921be2cb24281fa591f0b119b208b788adc48c2561d"}, ] [[package]] @@ -2782,13 +2874,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.1" +version = "7.4.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.1-py3-none-any.whl", hash = "sha256:460c9a59b14e27c602eb5ece2e47bec99dc5fc5f6513cf924a7d03a578991b1f"}, - {file = "pytest-7.4.1.tar.gz", hash = "sha256:2f2301e797521b23e4d2585a0a3d7b5e50fdddaaf7e7d6773ea26ddb17c213ab"}, + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, ] [package.dependencies] @@ -3003,6 +3095,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -3010,8 +3103,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -3028,6 +3128,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -3035,6 +3136,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -3339,73 +3441,80 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.49" +version = "2.0.20" description = "Database Abstraction Library" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "SQLAlchemy-1.4.49-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e126cf98b7fd38f1e33c64484406b78e937b1a280e078ef558b95bf5b6895f6"}, - {file = "SQLAlchemy-1.4.49-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:03db81b89fe7ef3857b4a00b63dedd632d6183d4ea5a31c5d8a92e000a41fc71"}, - {file = "SQLAlchemy-1.4.49-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:95b9df9afd680b7a3b13b38adf6e3a38995da5e162cc7524ef08e3be4e5ed3e1"}, - {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63e43bf3f668c11bb0444ce6e809c1227b8f067ca1068898f3008a273f52b09"}, - {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f835c050ebaa4e48b18403bed2c0fda986525896efd76c245bdd4db995e51a4c"}, - {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c21b172dfb22e0db303ff6419451f0cac891d2e911bb9fbf8003d717f1bcf91"}, - {file = "SQLAlchemy-1.4.49-cp310-cp310-win32.whl", hash = "sha256:5fb1ebdfc8373b5a291485757bd6431de8d7ed42c27439f543c81f6c8febd729"}, - {file = "SQLAlchemy-1.4.49-cp310-cp310-win_amd64.whl", hash = "sha256:f8a65990c9c490f4651b5c02abccc9f113a7f56fa482031ac8cb88b70bc8ccaa"}, - {file = "SQLAlchemy-1.4.49-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8923dfdf24d5aa8a3adb59723f54118dd4fe62cf59ed0d0d65d940579c1170a4"}, - {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9ab2c507a7a439f13ca4499db6d3f50423d1d65dc9b5ed897e70941d9e135b0"}, - {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5debe7d49b8acf1f3035317e63d9ec8d5e4d904c6e75a2a9246a119f5f2fdf3d"}, - {file = "SQLAlchemy-1.4.49-cp311-cp311-win32.whl", hash = "sha256:82b08e82da3756765c2e75f327b9bf6b0f043c9c3925fb95fb51e1567fa4ee87"}, - {file = "SQLAlchemy-1.4.49-cp311-cp311-win_amd64.whl", hash = "sha256:171e04eeb5d1c0d96a544caf982621a1711d078dbc5c96f11d6469169bd003f1"}, - {file = "SQLAlchemy-1.4.49-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:36e58f8c4fe43984384e3fbe6341ac99b6b4e083de2fe838f0fdb91cebe9e9cb"}, - {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b31e67ff419013f99ad6f8fc73ee19ea31585e1e9fe773744c0f3ce58c039c30"}, - {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c14b29d9e1529f99efd550cd04dbb6db6ba5d690abb96d52de2bff4ed518bc95"}, - {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c40f3470e084d31247aea228aa1c39bbc0904c2b9ccbf5d3cfa2ea2dac06f26d"}, - {file = "SQLAlchemy-1.4.49-cp36-cp36m-win32.whl", hash = "sha256:706bfa02157b97c136547c406f263e4c6274a7b061b3eb9742915dd774bbc264"}, - {file = "SQLAlchemy-1.4.49-cp36-cp36m-win_amd64.whl", hash = "sha256:a7f7b5c07ae5c0cfd24c2db86071fb2a3d947da7bd487e359cc91e67ac1c6d2e"}, - {file = "SQLAlchemy-1.4.49-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:4afbbf5ef41ac18e02c8dc1f86c04b22b7a2125f2a030e25bbb4aff31abb224b"}, - {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24e300c0c2147484a002b175f4e1361f102e82c345bf263242f0449672a4bccf"}, - {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:201de072b818f8ad55c80d18d1a788729cccf9be6d9dc3b9d8613b053cd4836d"}, - {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653ed6817c710d0c95558232aba799307d14ae084cc9b1f4c389157ec50df5c"}, - {file = "SQLAlchemy-1.4.49-cp37-cp37m-win32.whl", hash = "sha256:647e0b309cb4512b1f1b78471fdaf72921b6fa6e750b9f891e09c6e2f0e5326f"}, - {file = "SQLAlchemy-1.4.49-cp37-cp37m-win_amd64.whl", hash = "sha256:ab73ed1a05ff539afc4a7f8cf371764cdf79768ecb7d2ec691e3ff89abbc541e"}, - {file = "SQLAlchemy-1.4.49-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:37ce517c011560d68f1ffb28af65d7e06f873f191eb3a73af5671e9c3fada08a"}, - {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1878ce508edea4a879015ab5215546c444233881301e97ca16fe251e89f1c55"}, - {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e8e608983e6f85d0852ca61f97e521b62e67969e6e640fe6c6b575d4db68557"}, - {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccf956da45290df6e809ea12c54c02ace7f8ff4d765d6d3dfb3655ee876ce58d"}, - {file = "SQLAlchemy-1.4.49-cp38-cp38-win32.whl", hash = "sha256:f167c8175ab908ce48bd6550679cc6ea20ae169379e73c7720a28f89e53aa532"}, - {file = "SQLAlchemy-1.4.49-cp38-cp38-win_amd64.whl", hash = "sha256:45806315aae81a0c202752558f0df52b42d11dd7ba0097bf71e253b4215f34f4"}, - {file = "SQLAlchemy-1.4.49-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b6d0c4b15d65087738a6e22e0ff461b407533ff65a73b818089efc8eb2b3e1de"}, - {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a843e34abfd4c797018fd8d00ffffa99fd5184c421f190b6ca99def4087689bd"}, - {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c890421651b45a681181301b3497e4d57c0d01dc001e10438a40e9a9c25ee77"}, - {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d26f280b8f0a8f497bc10573849ad6dc62e671d2468826e5c748d04ed9e670d5"}, - {file = "SQLAlchemy-1.4.49-cp39-cp39-win32.whl", hash = "sha256:ec2268de67f73b43320383947e74700e95c6770d0c68c4e615e9897e46296294"}, - {file = "SQLAlchemy-1.4.49-cp39-cp39-win_amd64.whl", hash = "sha256:bbdf16372859b8ed3f4d05f925a984771cd2abd18bd187042f24be4886c2a15f"}, - {file = "SQLAlchemy-1.4.49.tar.gz", hash = "sha256:06ff25cbae30c396c4b7737464f2a7fc37a67b7da409993b182b024cec80aed9"}, +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759b51346aa388c2e606ee206c0bc6f15a5299f6174d1e10cadbe4530d3c7a98"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1506e988ebeaaf316f183da601f24eedd7452e163010ea63dbe52dc91c7fc70e"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5768c268df78bacbde166b48be788b83dddaa2a5974b8810af422ddfe68a9bc8"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3f0dd6d15b6dc8b28a838a5c48ced7455c3e1fb47b89da9c79cc2090b072a50"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:243d0fb261f80a26774829bc2cee71df3222587ac789b7eaf6555c5b15651eed"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6eb6d77c31e1bf4268b4d61b549c341cbff9842f8e115ba6904249c20cb78a61"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-win32.whl", hash = "sha256:bcb04441f370cbe6e37c2b8d79e4af9e4789f626c595899d94abebe8b38f9a4d"}, + {file = "SQLAlchemy-2.0.20-cp310-cp310-win_amd64.whl", hash = "sha256:d32b5ffef6c5bcb452723a496bad2d4c52b346240c59b3e6dba279f6dcc06c14"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd81466bdbc82b060c3c110b2937ab65ace41dfa7b18681fdfad2f37f27acdd7"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6fe7d61dc71119e21ddb0094ee994418c12f68c61b3d263ebaae50ea8399c4d4"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4e571af672e1bb710b3cc1a9794b55bce1eae5aed41a608c0401885e3491179"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3364b7066b3c7f4437dd345d47271f1251e0cfb0aba67e785343cdbdb0fff08c"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1be86ccea0c965a1e8cd6ccf6884b924c319fcc85765f16c69f1ae7148eba64b"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1d35d49a972649b5080557c603110620a86aa11db350d7a7cb0f0a3f611948a0"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-win32.whl", hash = "sha256:27d554ef5d12501898d88d255c54eef8414576f34672e02fe96d75908993cf53"}, + {file = "SQLAlchemy-2.0.20-cp311-cp311-win_amd64.whl", hash = "sha256:411e7f140200c02c4b953b3dbd08351c9f9818d2bd591b56d0fa0716bd014f1e"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3c6aceebbc47db04f2d779db03afeaa2c73ea3f8dcd3987eb9efdb987ffa09a3"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d3f175410a6db0ad96b10bfbb0a5530ecd4fcf1e2b5d83d968dd64791f810ed"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8186be85da6587456c9ddc7bf480ebad1a0e6dcbad3967c4821233a4d4df57"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c3d99ba99007dab8233f635c32b5cd24fb1df8d64e17bc7df136cedbea427897"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:76fdfc0f6f5341987474ff48e7a66c3cd2b8a71ddda01fa82fedb180b961630a"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-win32.whl", hash = "sha256:d3793dcf5bc4d74ae1e9db15121250c2da476e1af8e45a1d9a52b1513a393459"}, + {file = "SQLAlchemy-2.0.20-cp37-cp37m-win_amd64.whl", hash = "sha256:79fde625a0a55220d3624e64101ed68a059c1c1f126c74f08a42097a72ff66a9"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:599ccd23a7146e126be1c7632d1d47847fa9f333104d03325c4e15440fc7d927"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1a58052b5a93425f656675673ef1f7e005a3b72e3f2c91b8acca1b27ccadf5f4"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79543f945be7a5ada9943d555cf9b1531cfea49241809dd1183701f94a748624"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63e73da7fb030ae0a46a9ffbeef7e892f5def4baf8064786d040d45c1d6d1dc5"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ce5e81b800a8afc870bb8e0a275d81957e16f8c4b62415a7b386f29a0cb9763"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb0d3e94c2a84215532d9bcf10229476ffd3b08f481c53754113b794afb62d14"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-win32.whl", hash = "sha256:8dd77fd6648b677d7742d2c3cc105a66e2681cc5e5fb247b88c7a7b78351cf74"}, + {file = "SQLAlchemy-2.0.20-cp38-cp38-win_amd64.whl", hash = "sha256:6f8a934f9dfdf762c844e5164046a9cea25fabbc9ec865c023fe7f300f11ca4a"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:26a3399eaf65e9ab2690c07bd5cf898b639e76903e0abad096cd609233ce5208"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4cde2e1096cbb3e62002efdb7050113aa5f01718035ba9f29f9d89c3758e7e4e"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b09ba72e4e6d341bb5bdd3564f1cea6095d4c3632e45dc69375a1dbe4e26ec"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b74eeafaa11372627ce94e4dc88a6751b2b4d263015b3523e2b1e57291102f0"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:77d37c1b4e64c926fa3de23e8244b964aab92963d0f74d98cbc0783a9e04f501"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eefebcc5c555803065128401a1e224a64607259b5eb907021bf9b175f315d2a6"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-win32.whl", hash = "sha256:3423dc2a3b94125094897118b52bdf4d37daf142cbcf26d48af284b763ab90e9"}, + {file = "SQLAlchemy-2.0.20-cp39-cp39-win_amd64.whl", hash = "sha256:5ed61e3463021763b853628aef8bc5d469fe12d95f82c74ef605049d810f3267"}, + {file = "SQLAlchemy-2.0.20-py3-none-any.whl", hash = "sha256:63a368231c53c93e2b67d0c5556a9836fdcd383f7e3026a39602aad775b14acf"}, + {file = "SQLAlchemy-2.0.20.tar.gz", hash = "sha256:ca8a5ff2aa7f3ade6c498aaafce25b1eaeabe4e42b73e25519183e4566a16fc6"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +typing-extensions = ">=4.2.0" [package.extras] -aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] -mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] mysql-connector = ["mysql-connector-python"] -oracle = ["cx-oracle (>=7)", "cx-oracle (>=7,<8)"] +oracle = ["cx-oracle (>=7)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] postgresql = ["psycopg2 (>=2.7)"] postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] sqlcipher = ["sqlcipher3-binary"] [[package]] @@ -4204,4 +4313,4 @@ postgresql = ["psycopg2cffi"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "4fa7c1db5527fdc9e0e6e43f800c8a0af0d3ed6242ca80f08b689ad138fc4ec0" +content-hash = "7cdc74ff49f9b4d0631152e7350f46f3ac2ebccde20d37d1b7c1c31560d8e114" diff --git a/pyproject.toml b/pyproject.toml index 0a3575360..f5ac9064b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,8 +40,8 @@ pgvector = "^0.1.7" psycopg2cffi = {version = "^2.9.0", optional = true} loguru = "^0.7.0" elasticsearch = "8.8.2" -pykx="^1.6.3" -kdbai_client = { path = "/Users/alexg/vector/kdbai-python-client" } +pykx = "^1.6.3" +kdbai-client = "^0.0.0.dev5" [tool.poetry.scripts] start = "server.main:start" From aca79faaef3dc5c98f470a5daa198a1ffbe1e4db Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Fri, 8 Sep 2023 16:18:09 +0200 Subject: [PATCH 17/28] Update notebook to try out the KDB.AI ChatGPT Retrieval Plugin. --- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 189 +++++++++--------- 1 file changed, 89 insertions(+), 100 deletions(-) diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index 24f6afacf..4b96298ad 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -11,72 +11,51 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "1. Install Python 3.10 if not already installed.\n", + "## Getting Started\n", "\n", - "2. Clone the `retrieval-app` repository:\n", + "### Prerequisites\n", "\n", - "```\n", - "git clone git@github.com:openai/retrieval-app.git\n", - "```\n", + "- Python 3\n", + "- Pip\n", + "- Git\n", "\n", - "3. Navigate to the app directory:\n", - "\n", - "```\n", - "cd /path/to/retrieval-app\n", - "```\n", - "\n", - "4. Install `poetry`:\n", + "### Install the KDB.AI ChatGPT Retrieval Plugin server app\n", "\n", "```\n", "pip install poetry\n", + "git clone https://github.com/KxSystems/chatgpt-retrieval-plugin@KDB.AI\n", + "cd chatgpt-retrieval-plugin\n", + "poetry install\n", "```\n", "\n", - "5. Create a new virtual environment:\n", + "### Run the KDB.AI ChatGPT Retrieval Plugin server app\n", "\n", "```\n", - "poetry env use python3.10\n", - "```\n", - "\n", - "6. Install the `retrieval-app` dependencies:\n", - "\n", - " Before installing the dependencies with poetry, we will need to add PyKX and a local KDBAI python package as a dependence in the `pyproject.toml` file. This can be done by by adding the following lines under `[tool.poetry.dependencies]`:\n", + "export BEARER_TOKEN='' # you can create your own bearer token on auth0.com\n", + "export DATASTORE=kdbai\n", + "export KDBAI_ENDPOINT=''\n", + "export KDBAI_API_KEY=''\n", + "export OPENAI_API_KEY='' # You can get a free API key on https://platform.openai.com\n", "\n", - "* __pykx = \"^1.6.3\"__\n", - "* __kdbai = { path = \"path/to/kdbai-python-client\" }__\n", + "poetry run start\n", + "```\n", "\n", - " Once these have been added, install dependencies to the poetry environment:\n", + "### Install a separate Jupyter environment to run this notebook\n", "\n", "```\n", - "poetry install\n", + "pip install datasets jupyter openai tqdm\n", "```\n", "\n", - "7. Set up the KDB.AI Cloud Server\n", - " \n", - " Sign up for an account [here](https://test.qa.cld.kx.com/kdbai/signup/) and verify your email to receive your host url (access endpoint) and KDB.AI API key.\n", - "\n", - "\n", - "8. Set app environment variables:\n", - "\n", - "* `BEARER_TOKEN`: Secret token used by the app to authorize incoming requests. The token can be generated using [jwt.io](https://jwt.io/).\n", - "* `OPENAI_API_KEY`: The OpenAI API key used for generating embeddings with the `text-embedding-ada-002` model. [Get an API key here](https://platform.openai.com/account/api-keys)!\n", - "\n", - "\n", - "9. Set `KDBAI`-specific environment variables:\n", + "### Run Jupyter\n", "\n", - "* `DATASTORE`: set to `kdbai`\n", - "* `KDBAI_ENDPOINT`: set to your Cloud host url ('https://ui.qa.cld.kx.com/instance/abcde12345' - omit '/api/v1/config/table')\n", - "* `KDBAI_API_KEY`: set to your Cloud KDB.AI API key\n", - "\n", - "10. Run the app with:\n", - "\n", - "```\n", - "poetry run start\n", "```\n", - "The ChatGPT plugin is ready to handle requests when `Application startup complete` is printed to the terminal.\n", + "export BEARER_TOKEN='' # Same bearer token as above\n", + "export OPENAI_API_KEY=''\n", "\n", - "When the application is up and running a FastAPI server exposes the ChatGPT plugin's endpoints for `upserting`, `querying`, and `deleting` documents.\n", + "jupyter notebook\n", + "```\n", "\n", - "During the start up of the application, a new table named `documents` is created in `KDB.AI` with default parameters `{type='flat', metric='L2', dims=1536}`. This table will contain vector embeddings of the data, with an HNSW index for similarity searching. " + "Then open this notebook in Jupyter." ] }, { @@ -86,12 +65,13 @@ "outputs": [], "source": [ "import os\n", + "from pprint import pprint\n", "import random\n", - "import requests\n", - "from tqdm.auto import tqdm\n", - "from datasets import load_dataset\n", "\n", - "import openai" + "from datasets import load_dataset\n", + "import openai\n", + "import requests\n", + "from tqdm.auto import tqdm" ] }, { @@ -262,19 +242,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "[{'text': 'Another approach to brain function is to examine the consequences of damage to specific brain areas. Even though it is protected by the skull and meninges, surrounded by cerebrospinal fluid, and isolated from the bloodstream by the blood–brain barrier, the delicate nature of the brain makes it vulnerable to numerous diseases and several types of damage. In humans, the effects of strokes and other types of brain damage have been a key source of information about brain function. Because there is no ability to experimentally control the nature of the damage, however, this information is often difficult to interpret. In animal studies, most commonly involving rats, it is possible to use electrodes or locally injected chemicals to produce precise patterns of damage and then examine the consequences for behavior.'}, {'text': 'Motor systems are areas of the brain that are directly or indirectly involved in producing body movements, that is, in activating muscles. Except for the muscles that control the eye, which are driven by nuclei in the midbrain, all the voluntary muscles in the body are directly innervated by motor neurons in the spinal cord and hindbrain. Spinal motor neurons are controlled both by neural circuits intrinsic to the spinal cord, and by inputs that descend from the brain. The intrinsic spinal circuits implement many reflex responses, and contain pattern generators for rhythmic movements such as walking or swimming. The descending connections from the brain allow for more sophisticated control.'}, {'text': \"The brain is an organ that serves as the center of the nervous system in all vertebrate and most invertebrate animals. Only a few invertebrates such as sponges, jellyfish, adult sea squirts and starfish do not have a brain; diffuse or localised nerve nets are present instead. The brain is located in the head, usually close to the primary sensory organs for such senses as vision, hearing, balance, taste, and smell. The brain is the most complex organ in a vertebrate's body. In a typical human, the cerebral cortex (the largest part) is estimated to contain 15–33 billion neurons, each connected by synapses to several thousand other neurons. These neurons communicate with one another by means of long protoplasmic fibers called axons, which carry trains of signal pulses called action potentials to distant parts of the brain or body targeting specific recipient cells.\"}]\n" + "{'text': 'Another approach to brain function is to examine the consequences of '\n", + " 'damage to specific brain areas. Even though it is protected by the '\n", + " 'skull and meninges, surrounded by cerebrospinal fluid, and isolated '\n", + " 'from the bloodstream by the blood–brain barrier, the delicate nature '\n", + " 'of the brain makes it vulnerable to numerous diseases and several '\n", + " 'types of damage. In humans, the effects of strokes and other types '\n", + " 'of brain damage have been a key source of information about brain '\n", + " 'function. Because there is no ability to experimentally control the '\n", + " 'nature of the damage, however, this information is often difficult '\n", + " 'to interpret. In animal studies, most commonly involving rats, it is '\n", + " 'possible to use electrodes or locally injected chemicals to produce '\n", + " 'precise patterns of damage and then examine the consequences for '\n", + " 'behavior.'}\n" ] } ], "source": [ - "# extract text data from the dataset and reformat\n", + "# extract text data from the dataset\n", "documents = [\n", " {\n", " 'text': r['context'],\n", " } for r in data.to_dict(orient='records')\n", "]\n", - "\n", - "print(documents[:3])" + "pprint(documents[0])" ] }, { @@ -283,7 +274,7 @@ "metadata": {}, "outputs": [], "source": [ - "# initialise a session with the vector database\n", + "# initialise an HTTP session with the KDB.AI ChatGPT Retrieval Plugin app\n", "s = requests.Session()" ] }, @@ -309,7 +300,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "45a268dbb3774613b8f79a15d8ac4f6b", + "model_id": "33d2e3d202a84b48ae427934b75e8d05", "version_major": 2, "version_minor": 0 }, @@ -357,7 +348,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[{'query': 'Are there fewer counties or members in the House of Representatives?'}, {'query': 'What county in Liberia has the largest number of people living there?'}, {'query': \"Which came first, the elections or Taylor's extradition?\"}, {'query': 'How has Portuguese influenced another mentioned language?'}, {'query': \"An adjective that describes characteristics from countries that are not of one's own is?\"}]\n" + "[{'query': 'What destination holds second place when taken nationally?'}, {'query': 'what location contained france?'}, {'query': 'The English word evangelical differs to the German usage which means?'}, {'query': 'The Christian faith shares what in common with most denominations?'}, {'query': 'Where was Hugo Gotius able to teach?'}]\n" ] } ], @@ -382,7 +373,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -419,10 +410,8 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": { - "scrolled": false - }, + "execution_count": 9, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -430,73 +419,67 @@ "text": [ "\n", "QUERY:\n", - "Are there fewer counties or members in the House of Representatives?\n", + "What destination holds second place when taken nationally?\n", "\n", "CONTEXT:\n", - "0.3: The Legislature is composed of the Senate and the House of Representatives. The House, led by a speaker, has 73 members apportioned among the 15 counties on the basis of the national census, with each county receiving a minimum of two members. Each House member represents an electoral district within a county as drawn by the National Elections Commission and is elected by a plurality of the popular vote of their district into a six-year term. The Senate is made up of two senators from each county for a total of 30 senators. Senators serve nine-year terms and are elected at-large by a plurality of the popular vote. The vice president serves as the President of the Senate, with a President pro tempore serving in their absence.\n", - "0.36: The House of Representatives currently has 59 members elected for a five-year term, 56 members by proportional representation and 3 observer members representing the Armenian, Latin and Maronite minorities. 24 seats are allocated to the Turkish community but remain vacant since 1964. The political environment is dominated by the communist AKEL, the liberal conservative Democratic Rally, the centrist Democratic Party, the social-democratic EDEK and the centrist EURO.KO. In 2008, Dimitris Christofias became the country's first Communist head of state. Due to his involvement in the 2012–13 Cypriot financial crisis, Christofias did not run for re-election in 2013. The Presidential election in 2013 resulted in Democratic Rally candidate Nicos Anastasiades winning 57.48% of the vote. As a result, Anastasiades was sworn in on and has been President since 28 February 2013.\n", - "0.36: Reapportionment following the 2010 United States Census gave the state two more seats in the House of Representatives. The legislature's redistricting, announced in 2012, was quickly challenged in court, on the grounds that it had unfairly benefited Republican interests. In 2015, the Florida Supreme Court ruled on appeal that the congressional districts had to be redrawn because of the legislature's violation of the Fair District Amendments to the state constitution passed in 2010; it accepted a new map in early December 2015.\n", + "0.4: 9%) in 2006, surpassing Madeira (in 2010), as the third most visited destination.[citation needed]\n", + "0.43: In the early 21st century, Republican voters control most of the state, especially in the more rural and suburban areas outside of the cities; Democratic strength is mostly confined to the urban cores of the four major cities, and is particularly strong in the cities of Nashville and Memphis. The latter area includes a large African-American population. Historically, Republicans had their greatest strength in East Tennessee before the 1960s. Tennessee's 1st and 2nd congressional districts, based in the Tri-Cities and Knoxville, respectively, are among the few historically Republican districts in the South. Those districts' residents supported the Union over the Confederacy during the Civil War; they identified with the GOP after the war and have stayed with that party ever since. The 1st has been in Republican hands continuously since 1881, and Republicans (or their antecedents) have held it for all but four years since 1859.\n", + "0.44: In its 2013 ParkScore ranking, The Trust for Public Land reported that the park system in New York City was the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis. ParkScore ranks urban park systems by a formula that analyzes median park size, park acres as percent of city area, the percent of city residents within a half-mile of a park, spending of park services per resident, and the number of playgrounds per 10,000 residents.\n", "\n", "RESPONSE: \n", - "There are fewer counties (15) than members in the House of Representatives (73).\n", + "Based on the provided information, the destination that holds the second place nationally is New York City. According to The Trust for Public Land's ParkScore ranking in 2013, the park system in New York City was ranked as the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "What county in Liberia has the largest number of people living there?\n", + "what location contained france?\n", "\n", "CONTEXT:\n", - "0.22: Liberia is divided into fifteen counties, which, in turn, are subdivided into a total of 90 districts and further subdivided into clans. The oldest counties are Grand Bassa and Montserrado, both founded in 1839 prior to Liberian independence. Gbarpolu is the newest county, created in 2001. Nimba is the largest of the counties in size at 11,551 km2 (4,460 sq mi), while Montserrado is the smallest at 1,909 km2 (737 sq mi). Montserrado is also the most populous county with 1,144,806 residents as of the 2008 census.\n", - "0.39: In 2010, the literacy rate of Liberia was estimated at 60.8% (64.8% for males and 56.8% for females). In some areas primary and secondary education is free and compulsory from the ages of 6 to 16, though enforcement of attendance is lax. In other areas children are required to pay a tuition fee to attend school. On average, children attain 10 years of education (11 for boys and 8 for girls). The country's education sector is hampered by inadequate schools and supplies, as well as a lack of qualified teachers.\n", - "0.4: The subsequent 2005 elections were internationally regarded as the most free and fair in Liberian history. Ellen Johnson Sirleaf, a Harvard-trained economist and former Minister of Finance, was elected as the first female president in Africa. Upon her inauguration, Sirleaf requested the extradition of Taylor from Nigeria and transferred him to the SCSL for trial in The Hague. In 2006, the government established a Truth and Reconciliation Commission to address the causes and crimes of the civil war.\n", + "0.38: On 14 June 1940, the German army marched into Paris, which had been declared an \"open city\". On 16–17 July 1942, following German orders, the French police and gendarmes arrested 12,884 Jews, including 4,115 children, and confined them during five days at the Vel d'Hiv (Vélodrome d'Hiver), from which they were transported by train to the extermination camp at Auschwitz. None of the children came back. On 25 August 1944, the city was liberated by the French 2nd Armoured Division and the 4th Infantry Division of the United States Army. General Charles de Gaulle led a huge and emotional crowd down the Champs Élysées towards Notre Dame de Paris, and made a rousing speech from the Hôtel de Ville.\n", + "0.38: Paris is located in northern central France. By road it is 450 kilometres (280 mi) south-east of London, 287 kilometres (178 mi) south of Calais, 305 kilometres (190 mi) south-west of Brussels, 774 kilometres (481 mi) north of Marseille, 385 kilometres (239 mi) north-east of Nantes, and 135 kilometres (84 mi) south-east of Rouen. Paris is located in the north-bending arc of the river Seine and includes two islands, the Île Saint-Louis and the larger Île de la Cité, which form the oldest part of the city. The river's mouth on the English Channel (La Manche) is about 233 mi (375 km) downstream of the city, established around 7600 BC. The city is spread widely on both banks of the river. Overall, the city is relatively flat, and the lowest point is 35 m (115 ft) above sea level.\n", + "0.39: The French Marines and naval infantry intended for the invasion of northern Germany were dispatched to reinforce the French Army of Châlons and fell into captivity at Sedan along with Napoleon III. A shortage of officers, following the capture of most of the professional French army at the Siege of Metz and at the Battle of Sedan, led naval officers to be sent from their ships to command hastily assembled reservists of the Garde Mobile. As the autumn storms of the North Sea forced the return of more of the French ships, the blockade of the north German ports diminished and in September 1870 the French navy abandoned the blockade for the winter. The rest of the navy retired to ports along the English Channel and remained in port for the rest of the war.\n", "\n", "RESPONSE: \n", - "The county in Liberia with the largest number of people living there is Montserrado. As of the 2008 census, Montserrado had a population of 1,144,806 residents.\n", + "France is a country located in Western Europe. It is bordered by several countries, including Belgium, Luxembourg, Germany, Switzerland, Italy, Spain, Andorra, and Monaco.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "Which came first, the elections or Taylor's extradition?\n", + "The English word evangelical differs to the German usage which means?\n", "\n", "CONTEXT:\n", - "0.4: The subsequent 2005 elections were internationally regarded as the most free and fair in Liberian history. Ellen Johnson Sirleaf, a Harvard-trained economist and former Minister of Finance, was elected as the first female president in Africa. Upon her inauguration, Sirleaf requested the extradition of Taylor from Nigeria and transferred him to the SCSL for trial in The Hague. In 2006, the government established a Truth and Reconciliation Commission to address the causes and crimes of the civil war.\n", - "0.41: Democratic Party candidates were consistently elected to local office, increasing the city's ties to the South and its dominant party. In 1861, Mayor Fernando Wood called on the aldermen to declare independence from Albany and the United States after the South seceded, but his proposal was not acted on. Anger at new military conscription laws during the American Civil War (1861–1865), which spared wealthier men who could afford to pay a $300 (equivalent to $5,766 in 2016) commutation fee to hire a substitute, led to the Draft Riots of 1863, whose most visible participants were ethnic Irish working class. The situation deteriorated into attacks on New York's elite, followed by attacks on black New Yorkers and their property after fierce competition for a decade between Irish immigrants and blacks for work.\n", - "0.42: The Times occasionally makes endorsements for foreign elections. In November 2012, it endorsed a second term for Barack Obama although it also expressed reservations about his foreign policy.\n", + "0.17: During the Reformation, the term was hardly used outside of the German politics. The word evangelical (German: evangelisch), which refers to the gospel, was much more widely used for those involved in the religious movement. Nowadays, this word is still preferred among some of the historical Protestant denominations, above all the ones in the German-speaking area such as the EKD. The German word evangelisch means Protestant, and is different from the German evangelikal, which refers to churches shaped by Evangelicalism. The English word evangelical usually refers to Evangelical Protestant churches, and therefore not to Protestantism as a whole. It traces its roots back to the Puritans in England, where Evangelicalism originated, and then was brought to the United States.\n", + "0.26: The word reformatorisch is used as an alternative for evangelisch in German, and is different from English reformed (German: reformiert), which refers to churches shaped by ideas of John Calvin, Huldrych Zwingli and other Reformed theologians.\n", + "0.34: It gained great momentum in the 18th and 19th centuries with the emergence of Methodism and the Great Awakenings in Britain and North America. The origins of Evangelicalism are usually traced back to the English Methodist movement, Nicolaus Zinzendorf, the Moravian Church, Lutheran pietism, Presbyterianism and Puritanism. Among leaders and major figures of the Evangelical Protestant movement were John Wesley, George Whitefield, Jonathan Edwards, Billy Graham, Harold John Ockenga, John Stott and Martyn Lloyd-Jones.\n", "\n", "RESPONSE: \n", - "Based on my knowledge, the elections came first. The subsequent 2005 elections in Liberia were internationally regarded as the most free and fair in Liberian history. Ellen Johnson Sirleaf was elected as the first female president in Africa. After her inauguration, Sirleaf requested the extradition of Charles Taylor from Nigeria and transferred him to the Special Court for Sierra Leone (SCSL) for trial in The Hague. Therefore, the elections preceded Taylor's extradition.\n", + "The German word \"evangelisch\" means Protestant, and is different from the German word \"evangelikal,\" which refers to churches shaped by Evangelicalism. In English, the word evangelical usually refers to Evangelical Protestant churches, and not to Protestantism as a whole.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "How has Portuguese influenced another mentioned language?\n", + "The Christian faith shares what in common with most denominations?\n", "\n", "CONTEXT:\n", - "0.32: Portugal's colonial history has long since been a cornerstone of its national identity, as has its geographic position at the south-western corner of Europe, looking out into the Atlantic Ocean. It was one of the last western colonial European powers to give up its overseas territories (among them Angola and Mozambique in 1975), turning over the administration of Macau to the People's Republic of China at the end of 1999. Consequently, it has both influenced and been influenced by cultures from former colonies or dependencies, resulting in immigration from these former territories for both economic and/or personal reasons. Portugal, long a country of emigration (the vast majority of Brazilians have Portuguese ancestry), has now become a country of net immigration, and not just from the last Indian (Portuguese until 1961), African (Portuguese until 1975), and Far East Asian (Portuguese until 1999) overseas territories.\n", - "0.33: According to Ethnologue, the lexical similarity between Catalan and other Romance languages is: 87% with Italian; 85% with Portuguese; 80% with Spanish; 76% with Ladin; 75% with Sardinian; and 73% with Romanian.\n", - "0.33: 14% of the population speaks the official language Portuguese, the language of government and national communication during centuries of colonial rule. 44% speak Kriol, a Portuguese-based creole language, which is effectively a national language of communication among groups. The remainder speak a variety of native African languages unique to ethnicities.\n", + "0.26: Various ecumenical movements have attempted cooperation or reorganization of the various divided Protestant denominations, according to various models of union, but divisions continue to outpace unions, as there is no overarching authority to which any of the churches owe allegiance, which can authoritatively define the faith. Most denominations share common beliefs in the major aspects of the Christian faith while differing in many secondary doctrines, although what is major and what is secondary is a matter of idiosyncratic belief.\n", + "0.28: A wide range of beliefs and practices is found across the world among those who call themselves Christian. Denominations and sects disagree on a common definition of \"Christianity\". For example, Timothy Beal notes the disparity of beliefs among those who identify as Christians in the United States as follows:\n", + "0.32: Baptists, like other Christians, are defined by doctrine—some of it common to all orthodox and evangelical groups and a portion of it distinctive to Baptists. Through the years, different Baptist groups have issued confessions of faith—without considering them to be creeds—to express their particular doctrinal distinctions in comparison to other Christians as well as in comparison to other Baptists. Most Baptists are evangelical in doctrine, but Baptist beliefs can vary due to the congregational governance system that gives autonomy to individual local Baptist churches. Historically, Baptists have played a key role in encouraging religious freedom and separation of church and state.\n", "\n", "RESPONSE: \n", - "According to the given information, Portuguese has influenced Kriol, a Portuguese-based creole language. Kriol is effectively a national language of communication among groups in Portugal. This influence is likely a result of Portugal's colonial history and the extensive use of Portuguese as the language of government and national communication during centuries of colonial rule.\n", + "The Christian faith shares common beliefs in the major aspects of the Christian faith with most denominations. This includes beliefs in the existence of one God, the divinity and humanity of Jesus Christ, the crucifixion and resurrection of Jesus, and the belief in salvation through faith in Jesus. Additionally, most denominations also affirm the authority of the Bible as the Word of God and the importance of prayer, worship, and discipleship.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "An adjective that describes characteristics from countries that are not of one's own is?\n", + "Where was Hugo Gotius able to teach?\n", "\n", "CONTEXT:\n", - "0.43: In most cases this single term is inadequate to describe the geographical range of their operations. The result is multiple definitions.\n", - "0.43: There is no universally accepted criterion for distinguishing two different languages from two dialects (i.e. varieties) of the same language. A number of rough measures exist, sometimes leading to contradictory results. The distinction is therefore subjective and depends on the user's frame of reference. For example, there is discussion about if the Limón Creole English must be considered as \"a kind\" of English or a different language. This creole is spoken in the Caribbean coast of Costa Rica (Central America) by descendant of Jamaican people. The position that Costa Rican linguists support depends on the University they belong.\n", - "0.44: These patterns of discrimination against non-whites have led some academic and other activists to advocate for use of the Portuguese term negro to encompass all African-descended people, in order to stimulate a \"black\" consciousness and identity. This proposal has been criticized since the term pardo is considered to include a wide range of multiracial people, such as caboclos (mestizos), assimilated Amerindians and tri-racials, not only people of partial African and European descent. Trying to identify this entire group as \"black\" would be a false imposition of a different identity from outside the culture and deny people their other, equally valid, ancestries and cultures. It seems a one-drop rule in reverse.\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "0.38: He then went to the University of Göttingen on a grant from the Rockefeller Foundation to study mathematics under David Hilbert.\n", + "0.39: Humbert of Romans, the master general of the order from 1254 to 1263, was a great administrator, as well as preacher and writer. It was under his tenure as master general that the sisters in the order were given official membership. Humbert was a great lover of languages, and encouraged linguistic studies among the Dominicans, primarily Arabic, because of the missionary work friars were pursuing amongst those led astray or forced to convert by Muslims in the Middle East. He also wanted his friars to reach excellence in their preaching, and this was his most lasting contribution to the order. The growth of the spirituality of young preachers was his first priority. He once cried to his students: \"...\n", + "0.39: Doctrinal development has had an important place in the restoration of the Preachers. Several institutions, besides those already mentioned, played important parts. Such is the Biblical school at Jerusalem, open to the religious of the order and to secular clerics, which publishes the Revue Biblique. The faculty of theology at the University of Fribourg, confided to the care of the Dominicans in 1890, is flourishing, and has about 250 students. The Pontificium Collegium Internationale Angelicum, the future Pontifical University of Saint Thomas Aquinas, Angelicum established at Rome in 1908 by Master Hyacinth Cormier, opened its doors to regulars and seculars for the study of the sacred sciences. In addition to the reviews above are the Revue Thomiste, founded by Père Thomas Coconnier (d. 1908), and the Analecta Ordinis Prædicatorum (1893).\n", + "\n", "RESPONSE: \n", - "The adjective that describes characteristics from countries that are not of one's own is \"foreign.\" However, it is important to note that the concept of \"foreignness\" can vary depending on the perspective or frame of reference of the individual or culture using the term.\n", + "Based on the provided knowledge, there is no information available specifically about Hugo Grotius and his teaching locations. The information I have pertains to other individuals and institutions.\n", "\n", "----------------------------------------------------------------------\n" ] @@ -556,28 +539,34 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ + "## One would need to restart the KDB.AI ChatGPT Retrieval Plugin server app\n", + "## after this, to recreate the table\n", "res = requests.delete(\n", " \"http://localhost:8000/delete\",\n", - "\n", " headers = {\n", " \"Authorization\": f\"Bearer {BEARER_TOKEN}\"\n", - " },\n", - " \n", + " }, \n", " json = {\n", " \"delete_all\": True\n", " }\n", - "\n", ")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, From 82a46f9d1686ee3593e3ab75d88f6d94126d99cc Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Fri, 8 Sep 2023 17:08:53 +0200 Subject: [PATCH 18/28] Fix getting start instructions for the KDB.aI ChatGPT Retrieval Plugin. --- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index 4b96298ad..cbda1701b 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -22,9 +22,9 @@ "### Install the KDB.AI ChatGPT Retrieval Plugin server app\n", "\n", "```\n", - "pip install poetry\n", - "git clone https://github.com/KxSystems/chatgpt-retrieval-plugin@KDB.AI\n", + "git clone https://github.com/KxSystems/chatgpt-retrieval-plugin -b KDB.AI\n", "cd chatgpt-retrieval-plugin\n", + "pip install poetry\n", "poetry install\n", "```\n", "\n", @@ -300,7 +300,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "33d2e3d202a84b48ae427934b75e8d05", + "model_id": "b84c895cf81a456db5654c7c0c53ff69", "version_major": 2, "version_minor": 0 }, @@ -348,7 +348,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[{'query': 'What destination holds second place when taken nationally?'}, {'query': 'what location contained france?'}, {'query': 'The English word evangelical differs to the German usage which means?'}, {'query': 'The Christian faith shares what in common with most denominations?'}, {'query': 'Where was Hugo Gotius able to teach?'}]\n" + "[{'query': 'what group is mentioned second to last?'}, {'query': 'What is the type of the third mentioned location?'}, {'query': 'What intangible object is central to the proper functioning of a lighting fixture?'}, {'query': 'What is the exception to the less bright form being a type of light meant to illuminate broadly?'}, {'query': 'Solid state lighting has increased because of what?'}]\n" ] } ], @@ -419,67 +419,67 @@ "text": [ "\n", "QUERY:\n", - "What destination holds second place when taken nationally?\n", + "what group is mentioned second to last?\n", "\n", "CONTEXT:\n", - "0.4: 9%) in 2006, surpassing Madeira (in 2010), as the third most visited destination.[citation needed]\n", - "0.43: In the early 21st century, Republican voters control most of the state, especially in the more rural and suburban areas outside of the cities; Democratic strength is mostly confined to the urban cores of the four major cities, and is particularly strong in the cities of Nashville and Memphis. The latter area includes a large African-American population. Historically, Republicans had their greatest strength in East Tennessee before the 1960s. Tennessee's 1st and 2nd congressional districts, based in the Tri-Cities and Knoxville, respectively, are among the few historically Republican districts in the South. Those districts' residents supported the Union over the Confederacy during the Civil War; they identified with the GOP after the war and have stayed with that party ever since. The 1st has been in Republican hands continuously since 1881, and Republicans (or their antecedents) have held it for all but four years since 1859.\n", - "0.44: In its 2013 ParkScore ranking, The Trust for Public Land reported that the park system in New York City was the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis. ParkScore ranks urban park systems by a formula that analyzes median park size, park acres as percent of city area, the percent of city residents within a half-mile of a park, spending of park services per resident, and the number of playgrounds per 10,000 residents.\n", + "0.43: Listing all finite simple groups was a major achievement in contemporary group theory. 1998 Fields Medal winner Richard Borcherds succeeded in proving the monstrous moonshine conjectures, a surprising and deep relation between the largest finite simple sporadic group—the \"monster group\"—and certain modular functions, a piece of classical complex analysis, and string theory, a theory supposed to unify the description of many physical phenomena.\n", + "0.44: note 2]\n", + "0.44: note 2]\n", "\n", "RESPONSE: \n", - "Based on the provided information, the destination that holds the second place nationally is New York City. According to The Trust for Public Land's ParkScore ranking in 2013, the park system in New York City was ranked as the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis.\n", + "The group mentioned second to last is the \"monster group,\" which is the largest finite simple sporadic group.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "what location contained france?\n", + "What is the type of the third mentioned location?\n", "\n", "CONTEXT:\n", - "0.38: On 14 June 1940, the German army marched into Paris, which had been declared an \"open city\". On 16–17 July 1942, following German orders, the French police and gendarmes arrested 12,884 Jews, including 4,115 children, and confined them during five days at the Vel d'Hiv (Vélodrome d'Hiver), from which they were transported by train to the extermination camp at Auschwitz. None of the children came back. On 25 August 1944, the city was liberated by the French 2nd Armoured Division and the 4th Infantry Division of the United States Army. General Charles de Gaulle led a huge and emotional crowd down the Champs Élysées towards Notre Dame de Paris, and made a rousing speech from the Hôtel de Ville.\n", - "0.38: Paris is located in northern central France. By road it is 450 kilometres (280 mi) south-east of London, 287 kilometres (178 mi) south of Calais, 305 kilometres (190 mi) south-west of Brussels, 774 kilometres (481 mi) north of Marseille, 385 kilometres (239 mi) north-east of Nantes, and 135 kilometres (84 mi) south-east of Rouen. Paris is located in the north-bending arc of the river Seine and includes two islands, the Île Saint-Louis and the larger Île de la Cité, which form the oldest part of the city. The river's mouth on the English Channel (La Manche) is about 233 mi (375 km) downstream of the city, established around 7600 BC. The city is spread widely on both banks of the river. Overall, the city is relatively flat, and the lowest point is 35 m (115 ft) above sea level.\n", - "0.39: The French Marines and naval infantry intended for the invasion of northern Germany were dispatched to reinforce the French Army of Châlons and fell into captivity at Sedan along with Napoleon III. A shortage of officers, following the capture of most of the professional French army at the Siege of Metz and at the Battle of Sedan, led naval officers to be sent from their ships to command hastily assembled reservists of the Garde Mobile. As the autumn storms of the North Sea forced the return of more of the French ships, the blockade of the north German ports diminished and in September 1870 the French navy abandoned the blockade for the winter. The rest of the navy retired to ports along the English Channel and remained in port for the rest of the war.\n", + "0.44: Upper Palaeolithic deposits, including bones of Homo sapiens, have been found in local caves, and artefacts dating from the Bronze Age to the Middle Iron Age have been found at Mount Batten showing that it was one of the main trading ports of the country at that time. An unidentified settlement named 'TAMARI OSTIA' (mouth/estuaries of the Tamar) is listed in Ptolemy's Geographia and is presumed to be located in the area of the modern city.\n", + "0.45: 29 East 32nd Street was the location of the first building owned by the Grolier Club between 1890 and 1917.\n", + "0.45: The city grew out towards the west of the boundaries of the peninsula formed by the River Aare. The Zytglogge tower marked the western boundary of the city from 1191 until 1256, when the Käfigturm took over this role until 1345. It was, in turn, succeeded by the Christoffelturm (formerly located close to the site of the modern-day railway station) until 1622. During the time of the Thirty Years' War, two new fortifications – the so-called big and small Schanze (entrenchment) – were built to protect the whole area of the peninsula.\n", "\n", "RESPONSE: \n", - "France is a country located in Western Europe. It is bordered by several countries, including Belgium, Luxembourg, Germany, Switzerland, Italy, Spain, Andorra, and Monaco.\n", + "The type of the third mentioned location is a city.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "The English word evangelical differs to the German usage which means?\n", + "What intangible object is central to the proper functioning of a lighting fixture?\n", "\n", "CONTEXT:\n", - "0.17: During the Reformation, the term was hardly used outside of the German politics. The word evangelical (German: evangelisch), which refers to the gospel, was much more widely used for those involved in the religious movement. Nowadays, this word is still preferred among some of the historical Protestant denominations, above all the ones in the German-speaking area such as the EKD. The German word evangelisch means Protestant, and is different from the German evangelikal, which refers to churches shaped by Evangelicalism. The English word evangelical usually refers to Evangelical Protestant churches, and therefore not to Protestantism as a whole. It traces its roots back to the Puritans in England, where Evangelicalism originated, and then was brought to the United States.\n", - "0.26: The word reformatorisch is used as an alternative for evangelisch in German, and is different from English reformed (German: reformiert), which refers to churches shaped by ideas of John Calvin, Huldrych Zwingli and other Reformed theologians.\n", - "0.34: It gained great momentum in the 18th and 19th centuries with the emergence of Methodism and the Great Awakenings in Britain and North America. The origins of Evangelicalism are usually traced back to the English Methodist movement, Nicolaus Zinzendorf, the Moravian Church, Lutheran pietism, Presbyterianism and Puritanism. Among leaders and major figures of the Evangelical Protestant movement were John Wesley, George Whitefield, Jonathan Edwards, Billy Graham, Harold John Ockenga, John Stott and Martyn Lloyd-Jones.\n", + "0.27: Lighting fixtures come in a wide variety of styles for various functions. The most important functions are as a holder for the light source, to provide directed light and to avoid visual glare. Some are very plain and functional, while some are pieces of art in themselves. Nearly any material can be used, so long as it can tolerate the excess heat and is in keeping with safety codes.\n", + "0.29: An important property of light fixtures is the luminous efficacy or wall-plug efficiency, meaning the amount of usable light emanating from the fixture per used energy, usually measured in lumen per watt. A fixture using replaceable light sources can also have its efficiency quoted as the percentage of light passed from the \"bulb\" to the surroundings. The more transparent the lighting fixture is, the higher efficacy. Shading the light will normally decrease efficacy but increase the directionality and the visual comfort probability.\n", + "0.36: Recessed lighting (often called \"pot lights\" in Canada, \"can lights\" or 'high hats\" in the US) is popular, with fixtures mounted into the ceiling structure so as to appear flush with it. These downlights can use narrow beam spotlights, or wider-angle floodlights, both of which are bulbs having their own reflectors. There are also downlights with internal reflectors designed to accept common 'A' lamps (light bulbs) which are generally less costly than reflector lamps. Downlights can be incandescent, fluorescent, HID (high intensity discharge) or LED.\n", "\n", "RESPONSE: \n", - "The German word \"evangelisch\" means Protestant, and is different from the German word \"evangelikal,\" which refers to churches shaped by Evangelicalism. In English, the word evangelical usually refers to Evangelical Protestant churches, and not to Protestantism as a whole.\n", + "The intangible object that is central to the proper functioning of a lighting fixture is light. Without the presence of light, a lighting fixture would not be able to fulfill its function of providing illumination.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "The Christian faith shares what in common with most denominations?\n", + "What is the exception to the less bright form being a type of light meant to illuminate broadly?\n", "\n", "CONTEXT:\n", - "0.26: Various ecumenical movements have attempted cooperation or reorganization of the various divided Protestant denominations, according to various models of union, but divisions continue to outpace unions, as there is no overarching authority to which any of the churches owe allegiance, which can authoritatively define the faith. Most denominations share common beliefs in the major aspects of the Christian faith while differing in many secondary doctrines, although what is major and what is secondary is a matter of idiosyncratic belief.\n", - "0.28: A wide range of beliefs and practices is found across the world among those who call themselves Christian. Denominations and sects disagree on a common definition of \"Christianity\". For example, Timothy Beal notes the disparity of beliefs among those who identify as Christians in the United States as follows:\n", - "0.32: Baptists, like other Christians, are defined by doctrine—some of it common to all orthodox and evangelical groups and a portion of it distinctive to Baptists. Through the years, different Baptist groups have issued confessions of faith—without considering them to be creeds—to express their particular doctrinal distinctions in comparison to other Christians as well as in comparison to other Baptists. Most Baptists are evangelical in doctrine, but Baptist beliefs can vary due to the congregational governance system that gives autonomy to individual local Baptist churches. Historically, Baptists have played a key role in encouraging religious freedom and separation of church and state.\n", + "0.34: The illuminated ceiling was once popular in the 1960s and 1970s but fell out of favor after the 1980s. This uses diffuser panels hung like a suspended ceiling below fluorescent lights, and is considered general lighting. Other forms include neon, which is not usually intended to illuminate anything else, but to actually be an artwork in itself. This would probably fall under accent lighting, though in a dark nightclub it could be considered general lighting.\n", + "0.38: Expansive interior light has been a feature of Gothic cathedrals since the first structure was opened. The metaphysics of light in the Middle Ages led to clerical belief in its divinity and the importance of its display in holy settings. Much of this belief was based on the writings of Pseudo-Dionysius, a sixth-century mystic whose book, The Celestial Hierarchy, was popular among monks in France. Pseudo-Dionysius held that all light, even light reflected from metals or streamed through windows, was divine. To promote such faith, the abbot in charge of the Saint-Denis church on the north edge of Paris, the Abbot Suger, encouraged architects remodeling the building to make the interior as bright as possible.\n", + "0.38: Lighting fixtures come in a wide variety of styles for various functions. The most important functions are as a holder for the light source, to provide directed light and to avoid visual glare. Some are very plain and functional, while some are pieces of art in themselves. Nearly any material can be used, so long as it can tolerate the excess heat and is in keeping with safety codes.\n", "\n", "RESPONSE: \n", - "The Christian faith shares common beliefs in the major aspects of the Christian faith with most denominations. This includes beliefs in the existence of one God, the divinity and humanity of Jesus Christ, the crucifixion and resurrection of Jesus, and the belief in salvation through faith in Jesus. Additionally, most denominations also affirm the authority of the Bible as the Word of God and the importance of prayer, worship, and discipleship.\n", + "The exception to the less bright form being a type of light meant to illuminate broadly is neon lighting. Neon lighting is not usually intended to illuminate anything else but is instead designed to be an artwork in itself. It is often used as accent lighting, although in a dark nightclub setting, it could be considered general lighting. Neon lighting is known for its vibrant colors and can create a unique and eye-catching ambiance.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "Where was Hugo Gotius able to teach?\n", + "Solid state lighting has increased because of what?\n", "\n", "CONTEXT:\n", - "0.38: He then went to the University of Göttingen on a grant from the Rockefeller Foundation to study mathematics under David Hilbert.\n", - "0.39: Humbert of Romans, the master general of the order from 1254 to 1263, was a great administrator, as well as preacher and writer. It was under his tenure as master general that the sisters in the order were given official membership. Humbert was a great lover of languages, and encouraged linguistic studies among the Dominicans, primarily Arabic, because of the missionary work friars were pursuing amongst those led astray or forced to convert by Muslims in the Middle East. He also wanted his friars to reach excellence in their preaching, and this was his most lasting contribution to the order. The growth of the spirituality of young preachers was his first priority. He once cried to his students: \"...\n", - "0.39: Doctrinal development has had an important place in the restoration of the Preachers. Several institutions, besides those already mentioned, played important parts. Such is the Biblical school at Jerusalem, open to the religious of the order and to secular clerics, which publishes the Revue Biblique. The faculty of theology at the University of Fribourg, confided to the care of the Dominicans in 1890, is flourishing, and has about 250 students. The Pontificium Collegium Internationale Angelicum, the future Pontifical University of Saint Thomas Aquinas, Angelicum established at Rome in 1908 by Master Hyacinth Cormier, opened its doors to regulars and seculars for the study of the sacred sciences. In addition to the reviews above are the Revue Thomiste, founded by Père Thomas Coconnier (d. 1908), and the Analecta Ordinis Prædicatorum (1893).\n", + "0.28: In recent years light emitting diodes (LEDs) are becoming increasingly efficient leading to an extraordinary increase in the use of solid state lighting. In many situations, controlling the light emission of LEDs may be done most effectively by using the principles of nonimaging optics.\n", + "0.31: citation needed] This new development revolutionized LED lighting, making high-power blue light sources practical, leading to the development of technologies like BlueRay, as well as allowing the bright high resolution screens of modern tablets and phones.[citation needed]\n", + "0.35: Among the challenges being faced to improve the efficiency of LED-based white light sources is the development of more efficient phosphors. As of 2010, the most efficient yellow phosphor is still the YAG phosphor, with less than 10% Stoke shift loss. Losses attributable to internal optical losses due to re-absorption in the LED chip and in the LED packaging itself account typically for another 10% to 30% of efficiency loss. Currently, in the area of phosphor LED development, much effort is being spent on optimizing these devices to higher light output and higher operation temperatures. For instance, the efficiency can be raised by adapting better package design or by using a more suitable type of phosphor. Conformal coating process is frequently used to address the issue of varying phosphor thickness.\n", "\n", "RESPONSE: \n", - "Based on the provided knowledge, there is no information available specifically about Hugo Grotius and his teaching locations. The information I have pertains to other individuals and institutions.\n", + "Solid state lighting has increased due to the increasing efficiency of light emitting diodes (LEDs) in recent years. The use of nonimaging optics principles has been effective in controlling the light emission of LEDs. This development has revolutionized LED lighting, allowing for practical high-power blue light sources and enabling technologies like Blu-Ray, as well as the bright high-resolution screens of modern devices such as tablets and phones.\n", "\n", "----------------------------------------------------------------------\n" ] From 110ee908ebb69ea2eb3c9ce4e8bbdcffe9c8c566 Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Tue, 12 Sep 2023 12:35:24 +0100 Subject: [PATCH 19/28] KXI-28991 updated pyproject.toml to kdbai-client=^0.1.1 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f5ac9064b..a0d78d638 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ psycopg2cffi = {version = "^2.9.0", optional = true} loguru = "^0.7.0" elasticsearch = "8.8.2" pykx = "^1.6.3" -kdbai-client = "^0.0.0.dev5" +kdbai-client = "^0.1.1" [tool.poetry.scripts] start = "server.main:start" From 6464128b2b0fb5ce7a53037f971ee126bedac186 Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Tue, 12 Sep 2023 14:57:35 +0100 Subject: [PATCH 20/28] KDB.AI updated QA notebook --- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 173 ++++++++++++------ 1 file changed, 121 insertions(+), 52 deletions(-) diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index cbda1701b..542dcc81e 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -7,6 +7,51 @@ "# KDB.AI for Q&A with ChatGPT Retrieval Plugin" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This example will demonstrate how to use the ChatGPT Retrieval Plugin to embed and store data in KDB.AI, as well as to query the embedded data. The plugin enables ChatGPT large language models, such as GPT-3.5, to be used for querying data that it wasn't trained on. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How does the ChatGPT Retrieval Plugin work?" + ] + }, + { + "attachments": { + "ddd5ff28-8281-4908-9c02-81954bffe57c.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABQAAAAI8CAYAAACu+wavAAAAAXNSR0IArs4c6QAAbwx0RVh0bXhmaWxlACUzQ214ZmlsZSUyMGhvc3QlM0QlMjJhcHAuZGlhZ3JhbXMubmV0JTIyJTIwbW9kaWZpZWQlM0QlMjIyMDIzLTA5LTExVDE1JTNBNTUlM0E0NC41OThaJTIyJTIwYWdlbnQlM0QlMjJNb3ppbGxhJTJGNS4wJTIwKFdpbmRvd3MlMjBOVCUyMDEwLjAlM0IlMjBXaW42NCUzQiUyMHg2NCklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkYxMTYuMC4wLjAlMjBTYWZhcmklMkY1MzcuMzYlMjBFZGclMkYxMTYuMC4xOTM4Ljc2JTIyJTIwZXRhZyUzRCUyMmRWZ2NJYk9MMVFwdFlSc3RyNjJGJTIyJTIwdmVyc2lvbiUzRCUyMjIxLjcuNCUyMiUyMHR5cGUlM0QlMjJkZXZpY2UlMjIlM0UlMEElMjAlMjAlM0NkaWFncmFtJTIwbmFtZSUzRCUyMlBhZ2UtMSUyMiUyMGlkJTNEJTIyLVp2bVBoYWlPcUYzS1NZTjBoUVclMjIlM0UlMEElMjAlMjAlMjAlMjAlM0NteEdyYXBoTW9kZWwlMjBkeCUzRCUyMjE1MzIlMjIlMjBkeSUzRCUyMjgzMiUyMiUyMGdyaWQlM0QlMjIwJTIyJTIwZ3JpZFNpemUlM0QlMjIxMCUyMiUyMGd1aWRlcyUzRCUyMjElMjIlMjB0b29sdGlwcyUzRCUyMjElMjIlMjBjb25uZWN0JTNEJTIyMSUyMiUyMGFycm93cyUzRCUyMjElMjIlMjBmb2xkJTNEJTIyMSUyMiUyMHBhZ2UlM0QlMjIxJTIyJTIwcGFnZVNjYWxlJTNEJTIyMSUyMiUyMHBhZ2VXaWR0aCUzRCUyMjE2NTQlMjIlMjBwYWdlSGVpZ2h0JTNEJTIyMTE2OSUyMiUyMGJhY2tncm91bmQlM0QlMjIlMjMxNDE0MTQlMjIlMjBtYXRoJTNEJTIyMCUyMiUyMHNoYWRvdyUzRCUyMjAlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlM0Nyb290JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjIwJTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMTklMjIlMjBzdHlsZSUzRCUyMnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjI1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC4yNSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNmOGNlY2MlM0JzdHJva2VDb2xvciUzRCUyM2I4NTQ1MCUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjYzMiUyMiUyMHklM0QlMjIyODAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjklMjIlMjBzdHlsZSUzRCUyMnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjc1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjYzMiUyMiUyMHklM0QlMjIzNjAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMSUyMiUyMHZhbHVlJTNEJTIyJTI2bHQlM0Jmb250JTIwc3R5bGUlM0QlMjZxdW90JTNCZm9udC1zaXplJTNBJTIwMjBweCUzQiUyNnF1b3QlM0IlMjZndCUzQiUyNmx0JTNCc3BhbiUyNmd0JTNCUkVUUklFVkFMJTIwUExVR0lOJTI2bHQlM0IlMkZzcGFuJTI2Z3QlM0IlMjZsdCUzQiUyRmZvbnQlMjZndCUzQiUyMiUyMHN0eWxlJTNEJTIycm91bmRlZCUzRDAlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQmh0bWwlM0QxJTNCZmlsbENvbG9yJTNEbm9uZSUzQnN0cm9rZVdpZHRoJTNENCUzQnN0cm9rZUNvbG9yJTNEJTIzRkZGRkZGJTNCZm9udENvbG9yJTNEJTIzRkZGRkZGJTNCZm9udFN0eWxlJTNEMCUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjIzODklMjIlMjB5JTNEJTIyMjQwJTIyJTIwd2lkdGglM0QlMjIyNDAlMjIlMjBoZWlnaHQlM0QlMjIxNjAlMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01NSUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QwLjUlM0JleGl0WSUzRDElM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmV4aXRQZXJpbWV0ZXIlM0QwJTNCZW50cnlYJTNEMS4wMSUzQmVudHJ5WSUzRDAuNDkyJTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmVudHJ5UGVyaW1ldGVyJTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMyUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTU0JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTMlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyc2hhcGUlM0RjeWxpbmRlcjMlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQmh0bWwlM0QxJTNCYm91bmRlZExibCUzRDElM0JiYWNrZ3JvdW5kT3V0bGluZSUzRDElM0JzaXplJTNEMTUlM0JmaWxsQ29sb3IlM0Rub25lJTNCc3Ryb2tlQ29sb3IlM0QlMjNGRkZGRkYlM0JzdHJva2VXaWR0aCUzRDQlM0Jmb250Q29sb3IlM0QlMjNGRkZGRkYlM0IlMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyMTE2OSUyMiUyMHklM0QlMjIyNDAlMjIlMjB3aWR0aCUzRCUyMjEyMCUyMiUyMGhlaWdodCUzRCUyMjE2MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTExJTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0RvcnRob2dvbmFsRWRnZVN0eWxlJTNCcm91bmRlZCUzRDAlM0JvcnRob2dvbmFsTG9vcCUzRDElM0JqZXR0eVNpemUlM0RhdXRvJTNCaHRtbCUzRDElM0JleGl0WCUzRDAuNTE0JTNCZXhpdFklM0QwLjk1MSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZXhpdFBlcmltZXRlciUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC41JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNCUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyMDAlMjIlMjB5JTNEJTIyMjgwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ0FycmF5JTIwYXMlM0QlMjJwb2ludHMlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjEyMCUyMiUyMHklM0QlMjIyODAlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZBcnJheSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTQlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0JEQVRBU0VUJTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMmVsbGlwc2UlM0JzaGFwZSUzRGNsb3VkJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0JodG1sJTNEMSUzQmZpbGxDb2xvciUzRG5vbmUlM0JzdHJva2VXaWR0aCUzRDIlM0JzdHJva2VDb2xvciUzRCUyM0ZGRkZGRiUzQmZvbnRDb2xvciUzRCUyM0ZGRkZGRiUzQiUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjIxMiUyMiUyMHklM0QlMjIxMDAlMjIlMjB3aWR0aCUzRCUyMjIxMCUyMiUyMGhlaWdodCUzRCUyMjEyMCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE2JTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmRhc2hlZCUzRDElM0JodG1sJTNEMSUzQmRhc2hQYXR0ZXJuJTNEMSUyMDMlM0JzdHJva2VXaWR0aCUzRDQlM0Jyb3VuZGVkJTNEMCUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC4yNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMSUzQmVudHJ5WSUzRDAuMjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZjhjZWNjJTNCc3Ryb2tlQ29sb3IlM0QlMjNiODU0NTAlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB3aWR0aCUzRCUyMjUwJTIyJTIwaGVpZ2h0JTNEJTIyNTAlMjIlMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI0MTAlMjIlMjB5JTNEJTIyMzAwJTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyNDYwJTIyJTIweSUzRCUyMjI1MCUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteEdlb21ldHJ5JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC00OCUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjI1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC41JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMTglMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC00NSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01MSUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjc1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQmVudHJ5WCUzRDAlM0JlbnRyeVklM0QwLjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMTglMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01MCUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI4ODIlMjIlMjB5JTNEJTIyMzYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQmZvbnQlMjBzdHlsZSUzRCUyNnF1b3QlM0Jmb250LXNpemUlM0ElMjAxOHB4JTNCJTIwZm9udC13ZWlnaHQlM0ElMjBub3JtYWwlM0IlMjZxdW90JTNCJTI2Z3QlM0JFTUJFRERJTkclMjBNT0RFTCUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQndoaXRlU3BhY2UlM0R3cmFwJTNCaHRtbCUzRDElM0JmaWxsQ29sb3IlM0Rub25lJTNCZm9udENvbG9yJTNEJTIzRkZGRkZGJTNCc3Ryb2tlQ29sb3IlM0QlMjNGRkZGRkYlM0JzdHJva2VXaWR0aCUzRDIlM0Jmb250U3R5bGUlM0QxJTIyJTIwdmVydGV4JTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIweCUzRCUyMjczOSUyMiUyMHklM0QlMjIyNDAlMjIlMjB3aWR0aCUzRCUyMjEyMCUyMiUyMGhlaWdodCUzRCUyMjE2MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTcwJTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQm9ydGhvZ29uYWxMb29wJTNEMSUzQmpldHR5U2l6ZSUzRGF1dG8lM0JodG1sJTNEMSUzQmV4aXRYJTNEMSUzQmV4aXRZJTNEMC4yNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMCUzQmVudHJ5WSUzRDAuNSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTIyJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNjUlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtODglMjIlMjBzdHlsZSUzRCUyMmVkZ2VTdHlsZSUzRG9ydGhvZ29uYWxFZGdlU3R5bGUlM0Jyb3VuZGVkJTNEMCUzQm9ydGhvZ29uYWxMb29wJTNEMSUzQmpldHR5U2l6ZSUzRGF1dG8lM0JodG1sJTNEMSUzQmVudHJ5WCUzRDAlM0JlbnRyeVklM0QwLjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC04MCUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyMDAlMjIlMjB5JTNEJTIyNjE5JTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ0FycmF5JTIwYXMlM0QlMjJwb2ludHMlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjEyMSUyMiUyMHklM0QlMjI2MTklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjEyMSUyMiUyMHklM0QlMjIzNjAlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZBcnJheSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTIyJTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQmZvbnQlMjBzdHlsZSUzRCUyNnF1b3QlM0Jmb250LXNpemUlM0ElMjAxOHB4JTNCJTI2cXVvdCUzQiUyNmd0JTNCQ0hBVEdQVCUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQndoaXRlU3BhY2UlM0R3cmFwJTNCaHRtbCUzRDElM0JmaWxsQ29sb3IlM0Rub25lJTNCc3Ryb2tlQ29sb3IlM0QlMjNGRkZGRkYlM0JzdHJva2VXaWR0aCUzRDIlM0Jmb250Q29sb3IlM0QlMjNGRkZGRkYlM0IlMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyMjAwJTIyJTIweSUzRCUyMjUyOSUyMiUyMHdpZHRoJTNEJTIyMTYwJTIyJTIwaGVpZ2h0JTNEJTIyMTIwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjUlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0Rub25lJTNCZGFzaGVkJTNEMSUzQmh0bWwlM0QxJTNCZGFzaFBhdHRlcm4lM0QxJTIwMyUzQnN0cm9rZVdpZHRoJTNENCUzQnJvdW5kZWQlM0QwJTNCZXhpdFglM0QwJTNCZXhpdFklM0QwLjc1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QxJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjQ2MCUyMiUyMHklM0QlMjI1MTAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI1MTAlMjIlMjB5JTNEJTIyNDYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTI4JTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmRhc2hlZCUzRDElM0JodG1sJTNEMSUzQmRhc2hQYXR0ZXJuJTNEMSUyMDMlM0JzdHJva2VXaWR0aCUzRDQlM0Jyb3VuZGVkJTNEMCUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC4yNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMSUzQmVudHJ5WSUzRDAuMjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZjhjZWNjJTNCc3Ryb2tlQ29sb3IlM0QlMjNiODU0NTAlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xOCUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjc1MiUyMiUyMHklM0QlMjI1MTAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI4NzIlMjIlMjB5JTNEJTIyMjYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTMwJTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmRhc2hlZCUzRDElM0JodG1sJTNEMSUzQmRhc2hQYXR0ZXJuJTNEMSUyMDMlM0JzdHJva2VXaWR0aCUzRDQlM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRDElM0JlbnRyeVklM0QwLjc1JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC43NSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xOCUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjY5MiUyMiUyMHklM0QlMjIzNDUlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI3NDIlMjIlMjB5JTNEJTIyMjk1JTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTY3JTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQm9ydGhvZ29uYWxMb29wJTNEMSUzQmpldHR5U2l6ZSUzRGF1dG8lM0JodG1sJTNEMSUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC41JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QxJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTM2JTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjIlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMzYlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0IlMjZsdCUzQmIlMjZndCUzQlVTRVIlMjBJTlBVVCUzQSUyMCUyNmx0JTNCJTJGYiUyNmd0JTNCJTI2bHQlM0JiciUyNmd0JTNCJTI2bHQlM0JpJTI2Z3QlM0IlMjZxdW90JTNCV2hvJTIwaXMlMjB0aGUlMjBjdXJyZW50JTIwVUslMjBQcmltZSUyME1pbmlzdGVyJTNGJTI2cXVvdCUzQiUyNmx0JTNCJTJGaSUyNmd0JTNCJTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQnN0cm9rZUNvbG9yJTNEbm9uZSUzQmZpbGxDb2xvciUzRG5vbmUlM0JhbGlnbiUzRGxlZnQlM0J2ZXJ0aWNhbEFsaWduJTNEbWlkZGxlJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0Jyb3VuZGVkJTNEMCUzQmZvbnRDb2xvciUzRCUyMzVjNzlhMyUzQiUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI0MTAlMjIlMjB5JTNEJTIyNjI5JTIyJTIwd2lkdGglM0QlMjIzMjIlMjIlMjBoZWlnaHQlM0QlMjI0MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTQzJTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmh0bWwlM0QxJTNCcm91bmRlZCUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTElMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwd2lkdGglM0QlMjI1MCUyMiUyMGhlaWdodCUzRCUyMjUwJTIyJTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyMjgwJTIyJTIweSUzRCUyMjQ1MiUyMiUyMGFzJTNEJTIyc291cmNlUG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjQ1MCUyMiUyMHklM0QlMjI0MzAlMjIlMjBhcyUzRCUyMnRhcmdldFBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNDQlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0RjbGFzc2ljJTNCaHRtbCUzRDElM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRDAuNSUzQmVudHJ5WSUzRDAlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0yMiUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB3aWR0aCUzRCUyMjUwJTIyJTIwaGVpZ2h0JTNEJTIyNTAlMjIlMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyNDUyJTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyNDUwJTIyJTIweSUzRCUyMjM5OSUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteEdlb21ldHJ5JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC02MyUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjUlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmVudHJ5WCUzRC0wLjAwNCUzQmVudHJ5WSUzRDAuMjQ5JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmVudHJ5UGVyaW1ldGVyJTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNDUlMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0zJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTQ1JTIyJTIwdmFsdWUlM0QlMjJlbWJlZGRlZCUyMGRhdGElMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQnN0cm9rZUNvbG9yJTNEbm9uZSUzQmZpbGxDb2xvciUzRG5vbmUlM0JhbGlnbiUzRGNlbnRlciUzQnZlcnRpY2FsQWxpZ24lM0RtaWRkbGUlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQnJvdW5kZWQlM0QwJTNCZm9udFNpemUlM0QxOCUzQmZvbnRDb2xvciUzRCUyM2Q3ODE3ZCUzQmZvbnRTdHlsZSUzRDElMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyOTY5JTIyJTIweSUzRCUyMjI2MCUyMiUyMHdpZHRoJTNEJTIyOTAlMjIlMjBoZWlnaHQlM0QlMjI0MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTYyJTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0RvcnRob2dvbmFsRWRnZVN0eWxlJTNCcm91bmRlZCUzRDAlM0JvcnRob2dvbmFsTG9vcCUzRDElM0JqZXR0eVNpemUlM0RhdXRvJTNCaHRtbCUzRDElM0JleGl0WCUzRDElM0JleGl0WSUzRDAuNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNELTAuMDA2JTNCZW50cnlZJTNEMC43NTElM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZW50cnlQZXJpbWV0ZXIlM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01MCUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTMlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTAlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0JlbWJlZGRlZCUyMHF1ZXJ5JTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQnN0cm9rZUNvbG9yJTNEbm9uZSUzQmZpbGxDb2xvciUzRG5vbmUlM0JhbGlnbiUzRGNlbnRlciUzQnZlcnRpY2FsQWxpZ24lM0RtaWRkbGUlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQnJvdW5kZWQlM0QwJTNCZm9udENvbG9yJTNEJTIzNWM3OWEzJTNCZm9udFN0eWxlJTNEMSUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI5NjklMjIlMjB5JTNEJTIyMzQwJTIyJTIwd2lkdGglM0QlMjI5MCUyMiUyMGhlaWdodCUzRCUyMjQwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTQlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0Jjb250ZXh0JTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQmFsaWduJTNEY2VudGVyJTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQnJlc2l6YWJsZSUzRDAlM0Jwb2ludHMlM0QlNUIlNUQlM0JhdXRvc2l6ZSUzRDElM0JzdHJva2VDb2xvciUzRG5vbmUlM0JmaWxsQ29sb3IlM0Rub25lJTNCZm9udENvbG9yJTNEJTIzNWM3OWEzJTNCZm9udFN0eWxlJTNEMSUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI5NjklMjIlMjB5JTNEJTIyNDI5JTIyJTIwd2lkdGglM0QlMjI5MCUyMiUyMGhlaWdodCUzRCUyMjQwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTclMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0Rub25lJTNCaHRtbCUzRDElM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRC0wLjAxMSUzQmVudHJ5WSUzRDAuNTE4JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmVudHJ5UGVyaW1ldGVyJTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTQlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwd2lkdGglM0QlMjI1MCUyMiUyMGhlaWdodCUzRCUyMjUwJTIyJTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyNzEyJTIyJTIweSUzRCUyMjQ0OSUyMiUyMGFzJTNEJTIyc291cmNlUG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjc4MiUyMiUyMHklM0QlMjIzODklMjIlMjBhcyUzRCUyMnRhcmdldFBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTglMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0RjbGFzc2ljJTNCaHRtbCUzRDElM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRDElM0JlbnRyeVklM0QwLjc1JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjcxMiUyMiUyMHklM0QlMjI0NTAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI2MzIlMjIlMjB5JTNEJTIyMzYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTY1JTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQmZvbnQlMjBzdHlsZSUzRCUyNnF1b3QlM0Jmb250LXNpemUlM0ElMjAxOHB4JTNCJTI2cXVvdCUzQiUyNmd0JTNCJTI2bHQlM0JiJTI2Z3QlM0JDSEFUR1BUJTIwT1VUUFVUJTNBJTIwJTI2bHQlM0IlMkZiJTI2Z3QlM0IlMjZsdCUzQmJyJTI2Z3QlM0IlMjZsdCUzQmklMjZndCUzQiUyNnF1b3QlM0JUaGUlMjBQcmltZSUyME1pbmlzdGVyJTIwb2YlMjB0aGUlMjBVSyUyMGluJTIwMjAyMyUyMGlzJTIwUmlzaGklMjBTdW5hayUyNnF1b3QlM0IlMjZsdCUzQiUyRmklMjZndCUzQiUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJ0ZXh0JTNCaHRtbCUzRDElM0JzdHJva2VDb2xvciUzRG5vbmUlM0JmaWxsQ29sb3IlM0Rub25lJTNCYWxpZ24lM0RsZWZ0JTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQndoaXRlU3BhY2UlM0R3cmFwJTNCcm91bmRlZCUzRDAlM0Jmb250Q29sb3IlM0QlMjM1Yzc5YTMlM0IlMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyNDEwJTIyJTIweSUzRCUyMjUwOSUyMiUyMHdpZHRoJTNEJTIyMzA5JTIyJTIwaGVpZ2h0JTNEJTIyNDAlMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC02OSUyMiUyMHZhbHVlJTNEJTIyJTIyJTIwc3R5bGUlM0QlMjJlbmRBcnJvdyUzRG5vbmUlM0JkYXNoZWQlM0QxJTNCaHRtbCUzRDElM0JkYXNoUGF0dGVybiUzRDElMjAzJTNCc3Ryb2tlV2lkdGglM0Q0JTNCcm91bmRlZCUzRDAlM0JleGl0WCUzRDAlM0JleGl0WSUzRDAuNzUlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjIlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwd2lkdGglM0QlMjI1MCUyMiUyMGhlaWdodCUzRCUyMjUwJTIyJTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyMzEwJTIyJTIweSUzRCUyMjY2OSUyMiUyMGFzJTNEJTIyc291cmNlUG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjM2MCUyMiUyMHklM0QlMjI2MTklMjIlMjBhcyUzRCUyMnRhcmdldFBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNzIlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0Rub25lJTNCZGFzaGVkJTNEMSUzQmh0bWwlM0QxJTNCZGFzaFBhdHRlcm4lM0QxJTIwMyUzQnN0cm9rZVdpZHRoJTNENCUzQnJvdW5kZWQlM0QwJTNCZW50cnlYJTNEMSUzQmVudHJ5WSUzRDAuMjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZXhpdFglM0QwLjUlM0JleGl0WSUzRDAlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjIlMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0yMiUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB3aWR0aCUzRCUyMjUwJTIyJTIwaGVpZ2h0JTNEJTIyNTAlMjIlMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyNTU5JTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyMzIwJTIyJTIweSUzRCUyMjUwOSUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NBcnJheSUyMGFzJTNEJTIycG9pbnRzJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyNTU5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGQXJyYXklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteEdlb21ldHJ5JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC03NiUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjUlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmVudHJ5WCUzRDAlM0JlbnRyeVklM0QwLjI1JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyMjgwJTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTc4JTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0RvcnRob2dvbmFsRWRnZVN0eWxlJTNCcm91bmRlZCUzRDAlM0JvcnRob2dvbmFsTG9vcCUzRDElM0JqZXR0eVNpemUlM0RhdXRvJTNCaHRtbCUzRDElM0JleGl0WCUzRDElM0JleGl0WSUzRDAuNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjM2MCUyMiUyMHklM0QlMjIzNTkuOTQxMTc2NDcwNTg4MyUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjI4MCUyMiUyMHklM0QlMjIzNjAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNzklMjIlMjB2YWx1ZSUzRCUyMiU1Q1VQU0VSVCUyMiUyMHN0eWxlJTNEJTIydGV4dCUzQmh0bWwlM0QxJTNCc3Ryb2tlQ29sb3IlM0Rub25lJTNCZmlsbENvbG9yJTNEbm9uZSUzQmFsaWduJTNEY2VudGVyJTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQndoaXRlU3BhY2UlM0R3cmFwJTNCcm91bmRlZCUzRDAlM0Jmb250U2l6ZSUzRDE4JTNCZm9udENvbG9yJTNEJTIzZDc4MTdkJTNCZm9udFN0eWxlJTNEMSUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjIyMDAlMjIlMjB5JTNEJTIyMjYwJTIyJTIwd2lkdGglM0QlMjI4MCUyMiUyMGhlaWdodCUzRCUyMjQwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtODAlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0IlNUNRVUVSWSUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJ0ZXh0JTNCaHRtbCUzRDElM0JzdHJva2VDb2xvciUzRG5vbmUlM0JmaWxsQ29sb3IlM0Rub25lJTNCYWxpZ24lM0RjZW50ZXIlM0J2ZXJ0aWNhbEFsaWduJTNEbWlkZGxlJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0Jyb3VuZGVkJTNEMCUzQmZvbnRDb2xvciUzRCUyMzVjNzlhMyUzQmZvbnRTdHlsZSUzRDElMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyMjAwJTIyJTIweSUzRCUyMjM0MCUyMiUyMHdpZHRoJTNEJTIyODAlMjIlMjBoZWlnaHQlM0QlMjI0MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTgyJTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQnNwYW4lMjZndCUzQiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTIwY29sb3IlM0QlMjZxdW90JTNCJTIzZmZmZmZmJTI2cXVvdCUzQiUyNmd0JTNCS0RCLkFJJTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjZsdCUzQiUyRnNwYW4lMjZndCUzQiUyMiUyMHN0eWxlJTNEJTIydGV4dCUzQmh0bWwlM0QxJTNCc3Ryb2tlQ29sb3IlM0Rub25lJTNCZmlsbENvbG9yJTNEbm9uZSUzQmFsaWduJTNEY2VudGVyJTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQndoaXRlU3BhY2UlM0R3cmFwJTNCcm91bmRlZCUzRDAlM0Jmb250U3R5bGUlM0QwJTIyJTIwdmVydGV4JTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIweCUzRCUyMjExOTklMjIlMjB5JTNEJTIyMjg4JTIyJTIwd2lkdGglM0QlMjI2MCUyMiUyMGhlaWdodCUzRCUyMjMwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtODQlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyc2hhcGUlM0RpbWFnZSUzQnZlcnRpY2FsTGFi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EAABEAABEACBkiIAAdBl6YYA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnIXQiAHkomQgEBEAABEAABEAABEAABEAABECgpAhAAXZZuCIAuS5iH3IUA6KFkIhQQAAEQAAEQAAEQAAEQAAEQAIGSIgAB0GXphgDosoR5yF0IgB5KJkIBARAAARAAARAAARAAARAAARAoKQIQAF2WbgiALkuYh9yFAOihZCIUEAABEAABEAABEAABEAABEACBkiIAAdBl6YYA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnIXQiAHkomQgEBEAABEAABEAABEAABEAABECgpAhAAXZZuCIAuS5iH3IUA6KFkIhQQAAEQAAEQAAEQAAEQAAEQAIGSIgAB0GXphgDosoR5yF0IgB5KJkIBARAAARAAARAAARAAARAAARAoKQIQAF2WbgiALkuYh9yFAOihZCIUEAABEAABEAABEAABEAABEACBkiIAAdBl6YYA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnI3VgBkIgag821TR4KEaGAAAiAAAiAAAiAAAiAAAiAAAiAgCcJQAB0WVohALosYR5yt6ahbZ4W/eyQlKKm1vm1fX97KFSEAgIgAAIgAAIgAAIgAAIgAAIgAAKeIgAB0GXphADosoR5yN1YARAVgB5KLkIBARAAARAAARAAARAAARAAARDwNAEIgC5LLwRAlyXMQ+6iAtBDyUQoIAACIAACIAACIAACIAACIAACJUUAAqDL0g0B0GUJ85C7qAD0UDIRCgiAAAiAAAiAAAiAAAiAAAiAQEkRgADosnRDAHRZwjzkLioAPZRMhAICIAACIAACIAACIAACIAACIFBSBCAAuizdEABdljAPuYsKQA8lE6GAAAiAAAiAAAiAAAiAAAiAAAiUFAEIgC5LNwRAlyXMQ+6iAtBDyUQoIAACIAACIAACIAAC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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![chatgpt-plugin.drawio (2).png](attachment:ddd5ff28-8281-4908-9c02-81954bffe57c.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The diagram above provides a high-level overview of the system, and explains how ChatGPT, the Retrieval Plugin, and KDB.AI all interact with one another. The system can be broken down into two main sub-systems: upserting (shown in red) and querying (shown in blue).\n", + "\n", + "\n", + "### Upserting\n", + "\n", + "Upserting is the process of taking our own dataset and uploading it to our vector database. In order to upsert data, we must pre-process it to remove any part we do not want to store in the database, change the format to a dictionary, and divide it into batches. When we call `/upsert`, each batch of data is embedded using an OpenAI LLM (Large Language Model), to generate a vector embedding for similarity search. The data and its embedding are then inserted into a KDB.AI table.\n", + "\n", + "\n", + "### Querying\n", + "\n", + "Querying involves taking an input query, or question, transforming it into an embedded vector, and running similarity search in the vector database to find its nearest neighbours - data with closest relevancy to the query. When we call `/query`, the input query is embedded with the same OpenAI LLM used for upserting, to generate a query vector. A similarity search algorithm running within KDB.AI will return the N closest matches with highest relevancy to the query. This \"context\" is then sent back to ChatGPT via the Retrieval Plugin. Finally, using this contextual information, ChatGPT outputs a human-like response to the query.\n", + "\n", + "Having an external source of data greatly increases the applicability of ChatGPT to different tasks. For example: GPT-3.5 can only answer questions with information it has seen during training, which is capped at 2021.. Therefore, if you asked it who the 2023 UK Prime Minister is, the model does not have the necessary information. However, if you were to download a dataset of political data up to the present day, ChatGPT would be able to use this data to answer the question. " + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -60,7 +105,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -76,7 +121,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -89,13 +134,12 @@ "source": [ "### Load Dataset from Hugging Face\n", "\n", - "The Adversarial_QA dataset is chosen for this demo.\n", - "The adversarial human annotation paradigm ensures that these datasets consist of questions that current state-of-the-art models find challenging." + "The Adversarial_QA dataset is chosen for this demonstration. It consists of questions that current state-of-the-art models find challenging, paired with contextual data that can be used to formulate an answer. Some of these questions have very poor grammar (\"What sare the benifts of the blood brain barrir?\"), and others are purposefully vague (\"What is at the highest level?\"), as shown in the example below:" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -221,7 +265,7 @@ "53 {'split': 'train', 'model_in_the_loop': 'Combi... " ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -233,9 +277,16 @@ "data.head()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To use this dataset for Q&A with ChatGPT, we need to insert the relevant data into our vector datastore - KDB.AI. The only column of data we will insert is the \"context\" column, which we reformat into a dictionary." + ] + }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -269,27 +320,27 @@ ] }, { - "cell_type": "code", - "execution_count": 5, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "# initialise an HTTP session with the KDB.AI ChatGPT Retrieval Plugin app\n", - "s = requests.Session()" + "### Insert data to the KDB.AI table" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 5, "metadata": {}, + "outputs": [], "source": [ - "### Insert data to the KDB.AI table" + "# initialise an HTTP session with the KDB.AI ChatGPT Retrieval Plugin app\n", + "s = requests.Session()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The `/upsert` instruction is used to insert data to the KDB.AI datastore in batches, with each batch being embedded with `text-embedding-ada-002` before it is added to the table." + "The `/upsert` instruction is used to insert data to the KDB.AI datastore in batches, with each batch being embedded with OpenAI Embedding Model `text-embedding-ada-002` before it is added to the table. We take our contextual data, which has been reformatted into a dictionary, and call `/upsert` on batches of 100 documents at a time. " ] }, { @@ -300,7 +351,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "b84c895cf81a456db5654c7c0c53ff69", + "model_id": "4aff214f16364f57b70ff92e4abccaae", "version_major": 2, "version_minor": 0 }, @@ -310,6 +361,17 @@ }, "metadata": {}, "output_type": "display_data" + }, + { + "ename": "NameError", + "evalue": "name 's' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 7\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m tqdm(\u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;28mlen\u001b[39m(documents), batchSize)):\n\u001b[1;32m 5\u001b[0m i_end \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mmin\u001b[39m(\u001b[38;5;28mlen\u001b[39m(documents), i\u001b[38;5;241m+\u001b[39mbatchSize)\n\u001b[0;32m----> 7\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43ms\u001b[49m\u001b[38;5;241m.\u001b[39mpost(\n\u001b[1;32m 8\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhttp://localhost:8000/upsert\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 9\u001b[0m \n\u001b[1;32m 10\u001b[0m headers \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 11\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAuthorization\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mBearer \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mBEARER_TOKEN\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 12\u001b[0m },\n\u001b[1;32m 13\u001b[0m \n\u001b[1;32m 14\u001b[0m json \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 15\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdocuments\u001b[39m\u001b[38;5;124m\"\u001b[39m: documents[i:i_end]\n\u001b[1;32m 16\u001b[0m }\n\u001b[1;32m 17\u001b[0m )\n", + "\u001b[0;31mNameError\u001b[0m: name 's' is not defined" + ] } ], "source": [ @@ -339,16 +401,23 @@ "### Query the KDB.AI table" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can take the list of questions from our dataset and format them into a dictionary. We will randomly choose 5 of these questions to be our queries in this example." + ] + }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[{'query': 'what group is mentioned second to last?'}, {'query': 'What is the type of the third mentioned location?'}, {'query': 'What intangible object is central to the proper functioning of a lighting fixture?'}, {'query': 'What is the exception to the less bright form being a type of light meant to illuminate broadly?'}, {'query': 'Solid state lighting has increased because of what?'}]\n" + "[{'query': 'What is the third part of the death penalty process?'}, {'query': 'Name one of the Panglong Conference negotiators who had a professional title.'}, {'query': 'How did Myanmar increase their rating by 1?'}, {'query': 'How are nats paid tribute to in Bamar culture?'}, {'query': 'When did the military begin its transition?'}]\n" ] } ], @@ -368,7 +437,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `/query` instruction is used to extract relevant information from the KDB.AI datastore. The queries are embedded into vectors, and a similarity search algorithm is used to calculate its nearest neighbours, representing the most relevant entries in the table." + "The `/query` instruction is used to extract relevant information from the KDB.AI datastore. The queries are embedded into vectors, and a similarity search algorithm is used to calculate its nearest neighbours, representing the most relevant entries in the table. " ] }, { @@ -405,7 +474,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the cell below, we iterate through each query and its results, and pass this data to ChatGPT, which uses it to respond to the query with natural language." + "In the cell below, we iterate through each query and its results, and pass this data to ChatGPT, which uses it to respond to the query with natural language. Here, you can see the three \"nearest neighbour\" pieces of context that ChatGPT uses to form its answer." ] }, { @@ -419,67 +488,67 @@ "text": [ "\n", "QUERY:\n", - "what group is mentioned second to last?\n", + "When was the half dollar last issued by the government?\n", "\n", "CONTEXT:\n", - "0.43: Listing all finite simple groups was a major achievement in contemporary group theory. 1998 Fields Medal winner Richard Borcherds succeeded in proving the monstrous moonshine conjectures, a surprising and deep relation between the largest finite simple sporadic group—the \"monster group\"—and certain modular functions, a piece of classical complex analysis, and string theory, a theory supposed to unify the description of many physical phenomena.\n", - "0.44: note 2]\n", - "0.44: note 2]\n", + "0.33: The Gold Standard Act of 1900 abandoned the bimetallic standard and defined the dollar as 23.22 grains (1.505 g) of gold, equivalent to setting the price of 1 troy ounce of gold at $20.67. Silver coins continued to be issued for circulation until 1964, when all silver was removed from dimes and quarters, and the half dollar was reduced to 40% silver. Silver half dollars were last issued for circulation in 1970. Gold coins were confiscated by Executive Order 6102 issued in 1933 by Franklin Roosevelt. The gold standard was changed to 13.71 grains (0.888 g), equivalent to setting the price of 1 troy ounce of gold at $35. This standard persisted until 1968.\n", + "0.34: Early releases of the Washington coin included error coins shipped primarily from the Philadelphia mint to Florida and Tennessee banks. Highly sought after by collectors, and trading for as much as $850 each within a week of discovery, the error coins were identified by the absence of the edge impressions \"E PLURIBUS UNUM IN GOD WE TRUST 2007 P\". The mint of origin is generally accepted to be mostly Philadelphia, although identifying the source mint is impossible without opening a mint pack also containing marked units. Edge lettering is minted in both orientations with respect to \"heads\", some amateur collectors were initially duped into buying \"upside down lettering error\" coins. Some cynics also erroneously point out that the Federal Reserve makes more profit from dollar bills than dollar coins because they wear out in a few years, whereas coins are more permanent.\n", + "0.35: Currently printed denominations are $1, $2, $5, $10, $20, $50, and $100. Notes above the $100 denomination stopped being printed in 1946 and were officially withdrawn from circulation in 1969. These notes were used primarily in inter-bank transactions or by organized crime; it was the latter usage that prompted President Richard Nixon to issue an executive order in 1969 halting their use. With the advent of electronic banking, they became less necessary. Notes in denominations of $500, $1,000, $5,000, $10,000 and $100,000 were all produced at one time; see large denomination bills in U.S. currency for details. These notes are now collectors' items and are worth more than their face value to collectors.\n", "\n", "RESPONSE: \n", - "The group mentioned second to last is the \"monster group,\" which is the largest finite simple sporadic group.\n", + "The half dollar was last issued for circulation by the government in 1970.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "What is the type of the third mentioned location?\n", + "How were some collectors fooled when seeking error coins?\n", "\n", "CONTEXT:\n", - "0.44: Upper Palaeolithic deposits, including bones of Homo sapiens, have been found in local caves, and artefacts dating from the Bronze Age to the Middle Iron Age have been found at Mount Batten showing that it was one of the main trading ports of the country at that time. An unidentified settlement named 'TAMARI OSTIA' (mouth/estuaries of the Tamar) is listed in Ptolemy's Geographia and is presumed to be located in the area of the modern city.\n", - "0.45: 29 East 32nd Street was the location of the first building owned by the Grolier Club between 1890 and 1917.\n", - "0.45: The city grew out towards the west of the boundaries of the peninsula formed by the River Aare. The Zytglogge tower marked the western boundary of the city from 1191 until 1256, when the Käfigturm took over this role until 1345. It was, in turn, succeeded by the Christoffelturm (formerly located close to the site of the modern-day railway station) until 1622. During the time of the Thirty Years' War, two new fortifications – the so-called big and small Schanze (entrenchment) – were built to protect the whole area of the peninsula.\n", + "0.27: Early releases of the Washington coin included error coins shipped primarily from the Philadelphia mint to Florida and Tennessee banks. Highly sought after by collectors, and trading for as much as $850 each within a week of discovery, the error coins were identified by the absence of the edge impressions \"E PLURIBUS UNUM IN GOD WE TRUST 2007 P\". The mint of origin is generally accepted to be mostly Philadelphia, although identifying the source mint is impossible without opening a mint pack also containing marked units. Edge lettering is minted in both orientations with respect to \"heads\", some amateur collectors were initially duped into buying \"upside down lettering error\" coins. Some cynics also erroneously point out that the Federal Reserve makes more profit from dollar bills than dollar coins because they wear out in a few years, whereas coins are more permanent.\n", + "0.4: The fallacy of this argument arises because new notes printed to replace worn out notes, which have been withdrawn from circulation, bring in no net revenue to the government to offset the costs of printing new notes and destroying the old ones. As most vending machines are incapable of making change in banknotes, they commonly accept only $1 bills, though a few will give change in dollar coins.\n", + "0.42: In 1982, the US Mint began minting pennies coated in copper but made primarily of zinc. With the new zinc pennies, there is the potential for zinc toxicosis, which can be fatal. One reported case of chronic ingestion of 425 pennies (over 1 kg of zinc) resulted in death due to gastrointestinal bacterial and fungal sepsis, whereas another patient, who ingested 12 grams of zinc, only showed lethargy and ataxia (gross lack of coordination of muscle movements). Several other cases have been reported of humans suffering zinc intoxication by the ingestion of zinc coins.\n", "\n", "RESPONSE: \n", - "The type of the third mentioned location is a city.\n", + "Some collectors were initially fooled when seeking error coins because some of the early releases of the Washington coin included error coins with edge lettering minted in both orientations with respect to \"heads\". This led some amateur collectors to mistakenly believe that the \"upside down lettering\" was an error, when in fact it was a normal variation.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "What intangible object is central to the proper functioning of a lighting fixture?\n", + "What conclusion was drawn by the Phillips curve?\n", "\n", "CONTEXT:\n", - "0.27: Lighting fixtures come in a wide variety of styles for various functions. The most important functions are as a holder for the light source, to provide directed light and to avoid visual glare. Some are very plain and functional, while some are pieces of art in themselves. Nearly any material can be used, so long as it can tolerate the excess heat and is in keeping with safety codes.\n", - "0.29: An important property of light fixtures is the luminous efficacy or wall-plug efficiency, meaning the amount of usable light emanating from the fixture per used energy, usually measured in lumen per watt. A fixture using replaceable light sources can also have its efficiency quoted as the percentage of light passed from the \"bulb\" to the surroundings. The more transparent the lighting fixture is, the higher efficacy. Shading the light will normally decrease efficacy but increase the directionality and the visual comfort probability.\n", - "0.36: Recessed lighting (often called \"pot lights\" in Canada, \"can lights\" or 'high hats\" in the US) is popular, with fixtures mounted into the ceiling structure so as to appear flush with it. These downlights can use narrow beam spotlights, or wider-angle floodlights, both of which are bulbs having their own reflectors. There are also downlights with internal reflectors designed to accept common 'A' lamps (light bulbs) which are generally less costly than reflector lamps. Downlights can be incandescent, fluorescent, HID (high intensity discharge) or LED.\n", + "0.36: In his Prices and Production (1931), Hayek argued that the business cycle resulted from the central bank's inflationary credit expansion and its transmission over time, leading to a capital misallocation caused by the artificially low interest rates. Hayek claimed that \"the past instability of the market economy is the consequence of the exclusion of the most important regulator of the market mechanism, money, from itself being regulated by the market process\".\n", + "0.38: The value of the U.S. dollar was therefore no longer anchored to gold, and it fell upon the Federal Reserve to maintain the value of the U.S. currency. The Federal Reserve, however, continued to increase the money supply, resulting in stagflation and a rapidly declining value of the U.S. dollar in the 1970s. This was largely due to the prevailing economic view at the time that inflation and real economic growth were linked (the Phillips curve), and so inflation was regarded as relatively benign. Between 1965 and 1981, the U.S. dollar lost two thirds of its value.\n", + "0.4: Hayek's principal investigations in economics concerned capital, money, and the business cycle. Mises had earlier applied the concept of marginal utility to the value of money in his Theory of Money and Credit (1912), in which he also proposed an explanation for \"industrial fluctuations\" based on the ideas of the old British Currency School and of Swedish economist Knut Wicksell. Hayek used this body of work as a starting point for his own interpretation of the business cycle, elaborating what later became known as the \"Austrian Theory of the Business Cycle\". Hayek spelled out the Austrian approach in more detail in his book, published in 1929, an English translation of which appeared in 1933 as Monetary Theory and the Trade Cycle. There he argued for a monetary approach to the origins of the cycle.\n", "\n", "RESPONSE: \n", - "The intangible object that is central to the proper functioning of a lighting fixture is light. Without the presence of light, a lighting fixture would not be able to fulfill its function of providing illumination.\n", + "The Phillips curve, which was developed by economist A. W. Phillips, suggested a trade-off between inflation and unemployment. It concluded that there was an inverse relationship between the two variables, implying that as unemployment decreased, inflation would increase and vice versa. This view was widely accepted during the 1960s and 1970s, leading policymakers to believe that they could manipulate inflation and unemployment through fiscal and monetary policy. However, this view was challenged by the stagflation experience of the 1970\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "What is the exception to the less bright form being a type of light meant to illuminate broadly?\n", + "How did the motors being expensive reflect on the American inventor?\n", "\n", "CONTEXT:\n", - "0.34: The illuminated ceiling was once popular in the 1960s and 1970s but fell out of favor after the 1980s. This uses diffuser panels hung like a suspended ceiling below fluorescent lights, and is considered general lighting. Other forms include neon, which is not usually intended to illuminate anything else, but to actually be an artwork in itself. This would probably fall under accent lighting, though in a dark nightclub it could be considered general lighting.\n", - "0.38: Expansive interior light has been a feature of Gothic cathedrals since the first structure was opened. The metaphysics of light in the Middle Ages led to clerical belief in its divinity and the importance of its display in holy settings. Much of this belief was based on the writings of Pseudo-Dionysius, a sixth-century mystic whose book, The Celestial Hierarchy, was popular among monks in France. Pseudo-Dionysius held that all light, even light reflected from metals or streamed through windows, was divine. To promote such faith, the abbot in charge of the Saint-Denis church on the north edge of Paris, the Abbot Suger, encouraged architects remodeling the building to make the interior as bright as possible.\n", - "0.38: Lighting fixtures come in a wide variety of styles for various functions. The most important functions are as a holder for the light source, to provide directed light and to avoid visual glare. Some are very plain and functional, while some are pieces of art in themselves. Nearly any material can be used, so long as it can tolerate the excess heat and is in keeping with safety codes.\n", + "0.32: The first commutator DC electric motor capable of turning machinery was invented by the British scientist William Sturgeon in 1832. Following Sturgeon's work, a commutator-type direct-current electric motor made with the intention of commercial use was built by the American inventor Thomas Davenport, which he patented in 1837. The motors ran at up to 600 revolutions per minute, and powered machine tools and a printing press. Due to the high cost of primary battery power, the motors were commercially unsuccessful and Davenport went bankrupt. Several inventors followed Sturgeon in the development of DC motors but all encountered the same battery power cost issues. No electricity distribution had been developed at the time. Like Sturgeon's motor, there was no practical commercial market for these motors.\n", + "0.38: Induction motor improvements flowing from these inventions and innovations were such that a 100 horsepower (HP) induction motor currently has the same mounting dimensions as a 7.5 HP motor in 1897.\n", + "0.38: In 1824, the French physicist François Arago formulated the existence of rotating magnetic fields, termed Arago's rotations, which, by manually turning switches on and off, Walter Baily demonstrated in 1879 as in effect the first primitive induction motor. In the 1880s, many inventors were trying to develop workable AC motors because AC's advantages in long-distance high-voltage transmission were counterbalanced by the inability to operate motors on AC. The first alternating-current commutatorless induction motors were independently invented by Galileo Ferraris and Nikola Tesla, a working motor model having been demonstrated by the former in 1885 and by the latter in 1887. In 1888, the Royal Academy of Science of Turin published Ferraris' research detailing the foundations of motor operation while however concluding that \"the apparatus based on that principle could not be of any commercial importance as motor.\n", "\n", "RESPONSE: \n", - "The exception to the less bright form being a type of light meant to illuminate broadly is neon lighting. Neon lighting is not usually intended to illuminate anything else but is instead designed to be an artwork in itself. It is often used as accent lighting, although in a dark nightclub setting, it could be considered general lighting. Neon lighting is known for its vibrant colors and can create a unique and eye-catching ambiance.\n", + "The high cost of primary battery power for the motors developed by the American inventor Thomas Davenport reflected negatively on him. Despite his invention of a commutator-type direct-current electric motor and obtaining a patent in 1837, the motors were commercially unsuccessful because they were expensive to operate. As a result, Davenport went bankrupt, as the motors did not find a practical commercial market due to the high cost of power.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "Solid state lighting has increased because of what?\n", + "stepper motors contains?\n", "\n", "CONTEXT:\n", - "0.28: In recent years light emitting diodes (LEDs) are becoming increasingly efficient leading to an extraordinary increase in the use of solid state lighting. In many situations, controlling the light emission of LEDs may be done most effectively by using the principles of nonimaging optics.\n", - "0.31: citation needed] This new development revolutionized LED lighting, making high-power blue light sources practical, leading to the development of technologies like BlueRay, as well as allowing the bright high resolution screens of modern tablets and phones.[citation needed]\n", - "0.35: Among the challenges being faced to improve the efficiency of LED-based white light sources is the development of more efficient phosphors. As of 2010, the most efficient yellow phosphor is still the YAG phosphor, with less than 10% Stoke shift loss. Losses attributable to internal optical losses due to re-absorption in the LED chip and in the LED packaging itself account typically for another 10% to 30% of efficiency loss. Currently, in the area of phosphor LED development, much effort is being spent on optimizing these devices to higher light output and higher operation temperatures. For instance, the efficiency can be raised by adapting better package design or by using a more suitable type of phosphor. Conformal coating process is frequently used to address the issue of varying phosphor thickness.\n", + "0.29: Stepper motors are a type of motor frequently used when precise rotations are required. In a stepper motor an internal rotor containing PMs or a magnetically soft rotor with salient poles is controlled by a set of external magnets that are switched electronically. A stepper motor may also be thought of as a cross between a DC electric motor and a rotary solenoid. As each coil is energized in turn, the rotor aligns itself with the magnetic field produced by the energized field winding. Unlike a synchronous motor, in its application, the stepper motor may not rotate continuously; instead, it \"steps\"—starts and then quickly stops again—from one position to the next as field windings are energized and de-energized in sequence. Depending on the sequence, the rotor may turn forwards or backwards, and it may change direction, stop, speed up or slow down arbitrarily at any time.\n", + "0.34: Stepper motors were and still are often used in computer printers, optical scanners, and digital photocopiers to move the optical scanning element, the print head carriage (of dot matrix and inkjet printers), and the platen or feed rollers. Likewise, many computer plotters (which since the early 1990s have been replaced with large-format inkjet and laser printers) used rotary stepper motors for pen and platen movement; the typical alternatives here were either linear stepper motors or servomotors with closed-loop analog control systems.\n", + "0.39: A servo system differs from some stepper motor applications in that the position feedback is continuous while the motor is running; a stepper system relies on the motor not to \"miss steps\" for short term accuracy, although a stepper system may include a \"home\" switch or other element to provide long-term stability of control. For instance, when a typical dot matrix computer printer starts up, its controller makes the print head stepper motor drive to its left-hand limit, where a position sensor defines home position and stops stepping. As long as power is on, a bidirectional counter in the printer's microprocessor keeps track of print-head position.\n", "\n", "RESPONSE: \n", - "Solid state lighting has increased due to the increasing efficiency of light emitting diodes (LEDs) in recent years. The use of nonimaging optics principles has been effective in controlling the light emission of LEDs. This development has revolutionized LED lighting, allowing for practical high-power blue light sources and enabling technologies like Blu-Ray, as well as the bright high-resolution screens of modern devices such as tablets and phones.\n", + "Stepper motors contain an internal rotor that can have permanent magnets or salient poles. They are controlled by a set of external magnets that are switched electronically. The motor operates by aligning the rotor with the magnetic field produced by the energized field winding. Stepper motors can rotate in either direction, change direction, stop, speed up, or slow down arbitrarily at any time.\n", "\n", "----------------------------------------------------------------------\n" ] @@ -537,6 +606,13 @@ "### Delete the KDB.AI table" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To delete the KDB.AI table, run the code cell below. Once this is done, the ChatGPT Retrieval Plugin app will need to be restarted to create another table." + ] + }, { "cell_type": "code", "execution_count": 10, @@ -555,13 +631,6 @@ " }\n", ")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 09973ae063bc66afcbbc09dbb885716142da182f Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Tue, 12 Sep 2023 15:29:23 +0100 Subject: [PATCH 21/28] notebook and diagram --- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 303 ++---------------- .../kdbai/kdbai-chatgpt-overview.png | Bin 0 -> 90715 bytes 2 files changed, 18 insertions(+), 285 deletions(-) create mode 100644 examples/providers/kdbai/kdbai-chatgpt-overview.png diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index 542dcc81e..727a7e090 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -22,15 +22,10 @@ ] }, { - "attachments": { - "ddd5ff28-8281-4908-9c02-81954bffe57c.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABQAAAAI8CAYAAACu+wavAAAAAXNSR0IArs4c6QAAbwx0RVh0bXhmaWxlACUzQ214ZmlsZSUyMGhvc3QlM0QlMjJhcHAuZGlhZ3JhbXMubmV0JTIyJTIwbW9kaWZpZWQlM0QlMjIyMDIzLTA5LTExVDE1JTNBNTUlM0E0NC41OThaJTIyJTIwYWdlbnQlM0QlMjJNb3ppbGxhJTJGNS4wJTIwKFdpbmRvd3MlMjBOVCUyMDEwLjAlM0IlMjBXaW42NCUzQiUyMHg2NCklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkYxMTYuMC4wLjAlMjBTYWZhcmklMkY1MzcuMzYlMjBFZGclMkYxMTYuMC4xOTM4Ljc2JTIyJTIwZXRhZyUzRCUyMmRWZ2NJYk9MMVFwdFlSc3RyNjJGJTIyJTIwdmVyc2lvbiUzRCUyMjIxLjcuNCUyMiUyMHR5cGUlM0QlMjJkZXZpY2UlMjIlM0UlMEElMjAlMjAlM0NkaWFncmFtJTIwbmFtZSUzRCUyMlBhZ2UtMSUyMiUyMGlkJTNEJTIyLVp2bVBoYWlPcUYzS1NZTjBoUVclMjIlM0UlMEElMjAlMjAlMjAlMjAlM0NteEdyYXBoTW9kZWwlMjBkeCUzRCUyMjE1MzIlMjIlMjBkeSUzRCUyMjgzMiUyMiUyMGdyaWQlM0QlMjIwJTIyJTIwZ3JpZFNpemUlM0QlMjIxMCUyMiUyMGd1aWRlcyUzRCUyMjElMjIlMjB0b29sdGlwcyUzRCUyMjElMjIlMjBjb25uZWN0JTNEJTIyMSUyMiUyMGFycm93cyUzRCUyMjElMjIlMjBmb2xkJTNEJTIyMSUyMiUyMHBhZ2UlM0QlMjIxJTIyJTIwcGFnZVNjYWxlJTNEJTIyMSUyMiUyMHBhZ2VXaWR0aCUzRCUyMjE2NTQlMjIlMjBwYWdlSGVpZ2h0JTNEJTIyMTE2OSUyMiUyMGJhY2tncm91bmQlM0QlMjIlMjMxNDE0MTQlMjIlMjBtYXRoJTNEJTIyMCUyMiUyMHNoYWRvdyUzRCUyMjAlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlM0Nyb290JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjIwJTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMTklMjIlMjBzdHlsZSUzRCUyMnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjI1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC4yNSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNmOGNlY2MlM0JzdHJva2VDb2xvciUzRCUyM2I4NTQ1MCUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjYzMiUyMiUyMHklM0QlMjIyODAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjklMjIlMjBzdHlsZSUzRCUyMnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjc1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjYzMiUyMiUyMHklM0QlMjIzNjAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMSUyMiUyMHZhbHVlJTNEJTIyJTI2bHQlM0Jmb250JTIwc3R5bGUlM0QlMjZxdW90JTNCZm9udC1zaXplJTNBJTIwMjBweCUzQiUyNnF1b3QlM0IlMjZndCUzQiUyNmx0JTNCc3BhbiUyNmd0JTNCUkVUUklFVkFMJTIwUExVR0lOJTI2bHQlM0IlMkZzcGFuJTI2Z3QlM0IlMjZsdCUzQiUyRmZvbnQlMjZndCUzQiUyMiUyMHN0eWxlJTNEJTIycm91bmRlZCUzRDAlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQmh0bWwlM0QxJTNCZmlsbENvbG9yJTNEbm9uZSUzQnN0cm9rZVdpZHRoJTNENCUzQnN0cm9rZUNvbG9yJTNEJTIzRkZGRkZGJTNCZm9udENvbG9yJTNEJTIzRkZGRkZGJTNCZm9udFN0eWxlJTNEMCUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjIzODklMjIlMjB5JTNEJTIyMjQwJTIyJTIwd2lkdGglM0QlMjIyNDAlMjIlMjBoZWlnaHQlM0QlMjIxNjAlMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01NSUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QwLjUlM0JleGl0WSUzRDElM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmV4aXRQZXJpbWV0ZXIlM0QwJTNCZW50cnlYJTNEMS4wMSUzQmVudHJ5WSUzRDAuNDkyJTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmVudHJ5UGVyaW1ldGVyJTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMyUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTU0JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTMlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyc2hhcGUlM0RjeWxpbmRlcjMlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQmh0bWwlM0QxJTNCYm91bmRlZExibCUzRDElM0JiYWNrZ3JvdW5kT3V0bGluZSUzRDElM0JzaXplJTNEMTUlM0JmaWxsQ29sb3IlM0Rub25lJTNCc3Ryb2tlQ29sb3IlM0QlMjNGRkZGRkYlM0JzdHJva2VXaWR0aCUzRDQlM0Jmb250Q29sb3IlM0QlMjNGRkZGRkYlM0IlMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyMTE2OSUyMiUyMHklM0QlMjIyNDAlMjIlMjB3aWR0aCUzRCUyMjEyMCUyMiUyMGhlaWdodCUzRCUyMjE2MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTExJTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0RvcnRob2dvbmFsRWRnZVN0eWxlJTNCcm91bmRlZCUzRDAlM0JvcnRob2dvbmFsTG9vcCUzRDElM0JqZXR0eVNpemUlM0RhdXRvJTNCaHRtbCUzRDElM0JleGl0WCUzRDAuNTE0JTNCZXhpdFklM0QwLjk1MSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZXhpdFBlcmltZXRlciUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC41JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNCUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyMDAlMjIlMjB5JTNEJTIyMjgwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ0FycmF5JTIwYXMlM0QlMjJwb2ludHMlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjEyMCUyMiUyMHklM0QlMjIyODAlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZBcnJheSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTQlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0JEQVRBU0VUJTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMmVsbGlwc2UlM0JzaGFwZSUzRGNsb3VkJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0JodG1sJTNEMSUzQmZpbGxDb2xvciUzRG5vbmUlM0JzdHJva2VXaWR0aCUzRDIlM0JzdHJva2VDb2xvciUzRCUyM0ZGRkZGRiUzQmZvbnRDb2xvciUzRCUyM0ZGRkZGRiUzQiUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjIxMiUyMiUyMHklM0QlMjIxMDAlMjIlMjB3aWR0aCUzRCUyMjIxMCUyMiUyMGhlaWdodCUzRCUyMjEyMCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE2JTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmRhc2hlZCUzRDElM0JodG1sJTNEMSUzQmRhc2hQYXR0ZXJuJTNEMSUyMDMlM0JzdHJva2VXaWR0aCUzRDQlM0Jyb3VuZGVkJTNEMCUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC4yNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMSUzQmVudHJ5WSUzRDAuMjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZjhjZWNjJTNCc3Ryb2tlQ29sb3IlM0QlMjNiODU0NTAlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB3aWR0aCUzRCUyMjUwJTIyJTIwaGVpZ2h0JTNEJTIyNTAlMjIlMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI0MTAlMjIlMjB5JTNEJTIyMzAwJTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyNDYwJTIyJTIweSUzRCUyMjI1MCUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteEdlb21ldHJ5JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC00OCUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjI1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC41JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMTglMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC00NSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01MSUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjc1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQmVudHJ5WCUzRDAlM0JlbnRyeVklM0QwLjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMTglMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01MCUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI4ODIlMjIlMjB5JTNEJTIyMzYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQmZvbnQlMjBzdHlsZSUzRCUyNnF1b3QlM0Jmb250LXNpemUlM0ElMjAxOHB4JTNCJTIwZm9udC13ZWlnaHQlM0ElMjBub3JtYWwlM0IlMjZxdW90JTNCJTI2Z3QlM0JFTUJFRERJTkclMjBNT0RFTCUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQndoaXRlU3BhY2UlM0R3cmFwJTNCaHRtbCUzRDElM0JmaWxsQ29sb3IlM0Rub25lJTNCZm9udENvbG9yJTNEJTIzRkZGRkZGJTNCc3Ryb2tlQ29sb3IlM0QlMjNGRkZGRkYlM0JzdHJva2VXaWR0aCUzRDIlM0Jmb250U3R5bGUlM0QxJTIyJTIwdmVydGV4JTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIweCUzRCUyMjczOSUyMiUyMHklM0QlMjIyNDAlMjIlMjB3aWR0aCUzRCUyMjEyMCUyMiUyMGhlaWdodCUzRCUyMjE2MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTcwJTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQm9ydGhvZ29uYWxMb29wJTNEMSUzQmpldHR5U2l6ZSUzRGF1dG8lM0JodG1sJTNEMSUzQmV4aXRYJTNEMSUzQmV4aXRZJTNEMC4yNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMCUzQmVudHJ5WSUzRDAuNSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTIyJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNjUlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtODglMjIlMjBzdHlsZSUzRCUyMmVkZ2VTdHlsZSUzRG9ydGhvZ29uYWxFZGdlU3R5bGUlM0Jyb3VuZGVkJTNEMCUzQm9ydGhvZ29uYWxMb29wJTNEMSUzQmpldHR5U2l6ZSUzRGF1dG8lM0JodG1sJTNEMSUzQmVudHJ5WCUzRDAlM0JlbnRyeVklM0QwLjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC04MCUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyMDAlMjIlMjB5JTNEJTIyNjE5JTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ0FycmF5JTIwYXMlM0QlMjJwb2ludHMlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjEyMSUyMiUyMHklM0QlMjI2MTklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjEyMSUyMiUyMHklM0QlMjIzNjAlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZBcnJheSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTIyJTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQmZvbnQlMjBzdHlsZSUzRCUyNnF1b3QlM0Jmb250LXNpemUlM0ElMjAxOHB4JTNCJTI2cXVvdCUzQiUyNmd0JTNCQ0hBVEdQVCUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQndoaXRlU3BhY2UlM0R3cmFwJTNCaHRtbCUzRDElM0JmaWxsQ29sb3IlM0Rub25lJTNCc3Ryb2tlQ29sb3IlM0QlMjNGRkZGRkYlM0JzdHJva2VXaWR0aCUzRDIlM0Jmb250Q29sb3IlM0QlMjNGRkZGRkYlM0IlMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyMjAwJTIyJTIweSUzRCUyMjUyOSUyMiUyMHdpZHRoJTNEJTIyMTYwJTIyJTIwaGVpZ2h0JTNEJTIyMTIwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjUlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0Rub25lJTNCZGFzaGVkJTNEMSUzQmh0bWwlM0QxJTNCZGFzaFBhdHRlcm4lM0QxJTIwMyUzQnN0cm9rZVdpZHRoJTNENCUzQnJvdW5kZWQlM0QwJTNCZXhpdFglM0QwJTNCZXhpdFklM0QwLjc1JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QxJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjQ2MCUyMiUyMHklM0QlMjI1MTAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI1MTAlMjIlMjB5JTNEJTIyNDYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTI4JTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmRhc2hlZCUzRDElM0JodG1sJTNEMSUzQmRhc2hQYXR0ZXJuJTNEMSUyMDMlM0JzdHJva2VXaWR0aCUzRDQlM0Jyb3VuZGVkJTNEMCUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC4yNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMSUzQmVudHJ5WSUzRDAuMjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZjhjZWNjJTNCc3Ryb2tlQ29sb3IlM0QlMjNiODU0NTAlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xOCUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjc1MiUyMiUyMHklM0QlMjI1MTAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI4NzIlMjIlMjB5JTNEJTIyMjYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTMwJTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmRhc2hlZCUzRDElM0JodG1sJTNEMSUzQmRhc2hQYXR0ZXJuJTNEMSUyMDMlM0JzdHJva2VXaWR0aCUzRDQlM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRDElM0JlbnRyeVklM0QwLjc1JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC43NSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xOCUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTE4JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjY5MiUyMiUyMHklM0QlMjIzNDUlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI3NDIlMjIlMjB5JTNEJTIyMjk1JTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTY3JTIyJTIwc3R5bGUlM0QlMjJyb3VuZGVkJTNEMCUzQm9ydGhvZ29uYWxMb29wJTNEMSUzQmpldHR5U2l6ZSUzRGF1dG8lM0JodG1sJTNEMSUzQmV4aXRYJTNEMCUzQmV4aXRZJTNEMC41JTNCZXhpdER4JTNEMCUzQmV4aXREeSUzRDAlM0JlbnRyeVglM0QxJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTM2JTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjIlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMzYlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0IlMjZsdCUzQmIlMjZndCUzQlVTRVIlMjBJTlBVVCUzQSUyMCUyNmx0JTNCJTJGYiUyNmd0JTNCJTI2bHQlM0JiciUyNmd0JTNCJTI2bHQlM0JpJTI2Z3QlM0IlMjZxdW90JTNCV2hvJTIwaXMlMjB0aGUlMjBjdXJyZW50JTIwVUslMjBQcmltZSUyME1pbmlzdGVyJTNGJTI2cXVvdCUzQiUyNmx0JTNCJTJGaSUyNmd0JTNCJTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQnN0cm9rZUNvbG9yJTNEbm9uZSUzQmZpbGxDb2xvciUzRG5vbmUlM0JhbGlnbiUzRGxlZnQlM0J2ZXJ0aWNhbEFsaWduJTNEbWlkZGxlJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0Jyb3VuZGVkJTNEMCUzQmZvbnRDb2xvciUzRCUyMzVjNzlhMyUzQiUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI0MTAlMjIlMjB5JTNEJTIyNjI5JTIyJTIwd2lkdGglM0QlMjIzMjIlMjIlMjBoZWlnaHQlM0QlMjI0MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTQzJTIyJTIwdmFsdWUlM0QlMjIlMjIlMjBzdHlsZSUzRCUyMmVuZEFycm93JTNEbm9uZSUzQmh0bWwlM0QxJTNCcm91bmRlZCUzRDAlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0JmaWxsQ29sb3IlM0QlMjNkYWU4ZmMlM0JzdHJva2VDb2xvciUzRCUyMzZjOGViZiUzQnN0cm9rZVdpZHRoJTNENCUzQiUyMiUyMGVkZ2UlM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTElMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwd2lkdGglM0QlMjI1MCUyMiUyMGhlaWdodCUzRCUyMjUwJTIyJTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyMjgwJTIyJTIweSUzRCUyMjQ1MiUyMiUyMGFzJTNEJTIyc291cmNlUG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjQ1MCUyMiUyMHklM0QlMjI0MzAlMjIlMjBhcyUzRCUyMnRhcmdldFBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNDQlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0RjbGFzc2ljJTNCaHRtbCUzRDElM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRDAuNSUzQmVudHJ5WSUzRDAlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0yMiUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB3aWR0aCUzRCUyMjUwJTIyJTIwaGVpZ2h0JTNEJTIyNTAlMjIlMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyNDUyJTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyNDUwJTIyJTIweSUzRCUyMjM5OSUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteEdlb21ldHJ5JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC02MyUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjUlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmVudHJ5WCUzRC0wLjAwNCUzQmVudHJ5WSUzRDAuMjQ5JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmVudHJ5UGVyaW1ldGVyJTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNDUlMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0zJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTQ1JTIyJTIwdmFsdWUlM0QlMjJlbWJlZGRlZCUyMGRhdGElMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQnN0cm9rZUNvbG9yJTNEbm9uZSUzQmZpbGxDb2xvciUzRG5vbmUlM0JhbGlnbiUzRGNlbnRlciUzQnZlcnRpY2FsQWxpZ24lM0RtaWRkbGUlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQnJvdW5kZWQlM0QwJTNCZm9udFNpemUlM0QxOCUzQmZvbnRDb2xvciUzRCUyM2Q3ODE3ZCUzQmZvbnRTdHlsZSUzRDElMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyOTY5JTIyJTIweSUzRCUyMjI2MCUyMiUyMHdpZHRoJTNEJTIyOTAlMjIlMjBoZWlnaHQlM0QlMjI0MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTYyJTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0RvcnRob2dvbmFsRWRnZVN0eWxlJTNCcm91bmRlZCUzRDAlM0JvcnRob2dvbmFsTG9vcCUzRDElM0JqZXR0eVNpemUlM0RhdXRvJTNCaHRtbCUzRDElM0JleGl0WCUzRDElM0JleGl0WSUzRDAuNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNELTAuMDA2JTNCZW50cnlZJTNEMC43NTElM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZW50cnlQZXJpbWV0ZXIlM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC01MCUyMiUyMHRhcmdldCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTMlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTAlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0JlbWJlZGRlZCUyMHF1ZXJ5JTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQnN0cm9rZUNvbG9yJTNEbm9uZSUzQmZpbGxDb2xvciUzRG5vbmUlM0JhbGlnbiUzRGNlbnRlciUzQnZlcnRpY2FsQWxpZ24lM0RtaWRkbGUlM0J3aGl0ZVNwYWNlJTNEd3JhcCUzQnJvdW5kZWQlM0QwJTNCZm9udENvbG9yJTNEJTIzNWM3OWEzJTNCZm9udFN0eWxlJTNEMSUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI5NjklMjIlMjB5JTNEJTIyMzQwJTIyJTIwd2lkdGglM0QlMjI5MCUyMiUyMGhlaWdodCUzRCUyMjQwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTQlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0Jjb250ZXh0JTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjIlMjBzdHlsZSUzRCUyMnRleHQlM0JodG1sJTNEMSUzQmFsaWduJTNEY2VudGVyJTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQnJlc2l6YWJsZSUzRDAlM0Jwb2ludHMlM0QlNUIlNUQlM0JhdXRvc2l6ZSUzRDElM0JzdHJva2VDb2xvciUzRG5vbmUlM0JmaWxsQ29sb3IlM0Rub25lJTNCZm9udENvbG9yJTNEJTIzNWM3OWEzJTNCZm9udFN0eWxlJTNEMSUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI5NjklMjIlMjB5JTNEJTIyNDI5JTIyJTIwd2lkdGglM0QlMjI5MCUyMiUyMGhlaWdodCUzRCUyMjQwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTclMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0Rub25lJTNCaHRtbCUzRDElM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRC0wLjAxMSUzQmVudHJ5WSUzRDAuNTE4JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmVudHJ5UGVyaW1ldGVyJTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTQlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwd2lkdGglM0QlMjI1MCUyMiUyMGhlaWdodCUzRCUyMjUwJTIyJTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyNzEyJTIyJTIweSUzRCUyMjQ0OSUyMiUyMGFzJTNEJTIyc291cmNlUG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjc4MiUyMiUyMHklM0QlMjIzODklMjIlMjBhcyUzRCUyMnRhcmdldFBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNTglMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0RjbGFzc2ljJTNCaHRtbCUzRDElM0Jyb3VuZGVkJTNEMCUzQmVudHJ5WCUzRDElM0JlbnRyeVklM0QwLjc1JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHdpZHRoJTNEJTIyNTAlMjIlMjBoZWlnaHQlM0QlMjI1MCUyMiUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjcxMiUyMiUyMHklM0QlMjI0NTAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjI2MzIlMjIlMjB5JTNEJTIyMzYwJTIyJTIwYXMlM0QlMjJ0YXJnZXRQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTY1JTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQmZvbnQlMjBzdHlsZSUzRCUyNnF1b3QlM0Jmb250LXNpemUlM0ElMjAxOHB4JTNCJTI2cXVvdCUzQiUyNmd0JTNCJTI2bHQlM0JiJTI2Z3QlM0JDSEFUR1BUJTIwT1VUUFVUJTNBJTIwJTI2bHQlM0IlMkZiJTI2Z3QlM0IlMjZsdCUzQmJyJTI2Z3QlM0IlMjZsdCUzQmklMjZndCUzQiUyNnF1b3QlM0JUaGUlMjBQcmltZSUyME1pbmlzdGVyJTIwb2YlMjB0aGUlMjBVSyUyMGluJTIwMjAyMyUyMGlzJTIwUmlzaGklMjBTdW5hayUyNnF1b3QlM0IlMjZsdCUzQiUyRmklMjZndCUzQiUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJ0ZXh0JTNCaHRtbCUzRDElM0JzdHJva2VDb2xvciUzRG5vbmUlM0JmaWxsQ29sb3IlM0Rub25lJTNCYWxpZ24lM0RsZWZ0JTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQndoaXRlU3BhY2UlM0R3cmFwJTNCcm91bmRlZCUzRDAlM0Jmb250Q29sb3IlM0QlMjM1Yzc5YTMlM0IlMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyNDEwJTIyJTIweSUzRCUyMjUwOSUyMiUyMHdpZHRoJTNEJTIyMzA5JTIyJTIwaGVpZ2h0JTNEJTIyNDAlMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC02OSUyMiUyMHZhbHVlJTNEJTIyJTIyJTIwc3R5bGUlM0QlMjJlbmRBcnJvdyUzRG5vbmUlM0JkYXNoZWQlM0QxJTNCaHRtbCUzRDElM0JkYXNoUGF0dGVybiUzRDElMjAzJTNCc3Ryb2tlV2lkdGglM0Q0JTNCcm91bmRlZCUzRDAlM0JleGl0WCUzRDAlM0JleGl0WSUzRDAuNzUlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjIlMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIwd2lkdGglM0QlMjI1MCUyMiUyMGhlaWdodCUzRCUyMjUwJTIyJTIwcmVsYXRpdmUlM0QlMjIxJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyMzEwJTIyJTIweSUzRCUyMjY2OSUyMiUyMGFzJTNEJTIyc291cmNlUG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjM2MCUyMiUyMHklM0QlMjI2MTklMjIlMjBhcyUzRCUyMnRhcmdldFBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNzIlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyZW5kQXJyb3clM0Rub25lJTNCZGFzaGVkJTNEMSUzQmh0bWwlM0QxJTNCZGFzaFBhdHRlcm4lM0QxJTIwMyUzQnN0cm9rZVdpZHRoJTNENCUzQnJvdW5kZWQlM0QwJTNCZW50cnlYJTNEMSUzQmVudHJ5WSUzRDAuMjUlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCZXhpdFglM0QwLjUlM0JleGl0WSUzRDAlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2RhZThmYyUzQnN0cm9rZUNvbG9yJTNEJTIzNmM4ZWJmJTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwc291cmNlJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMjIlMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0yMiUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB3aWR0aCUzRCUyMjUwJTIyJTIwaGVpZ2h0JTNEJTIyNTAlMjIlMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyNTU5JTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214UG9pbnQlMjB4JTNEJTIyMzIwJTIyJTIweSUzRCUyMjUwOSUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NBcnJheSUyMGFzJTNEJTIycG9pbnRzJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyNTU5JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGQXJyYXklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteEdlb21ldHJ5JTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhDZWxsJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhDZWxsJTIwaWQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC03NiUyMiUyMHN0eWxlJTNEJTIyZWRnZVN0eWxlJTNEb3J0aG9nb25hbEVkZ2VTdHlsZSUzQnJvdW5kZWQlM0QwJTNCb3J0aG9nb25hbExvb3AlM0QxJTNCamV0dHlTaXplJTNEYXV0byUzQmh0bWwlM0QxJTNCZXhpdFglM0QxJTNCZXhpdFklM0QwLjUlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmVudHJ5WCUzRDAlM0JlbnRyeVklM0QwLjI1JTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQmZpbGxDb2xvciUzRCUyM2Y4Y2VjYyUzQnN0cm9rZUNvbG9yJTNEJTIzYjg1NDUwJTNCc3Ryb2tlV2lkdGglM0Q0JTNCJTIyJTIwZWRnZSUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTIwdGFyZ2V0JTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhQb2ludCUyMHglM0QlMjIyODAlMjIlMjB5JTNEJTIyMjgwJTIyJTIwYXMlM0QlMjJzb3VyY2VQb2ludCUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14R2VvbWV0cnklM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTc4JTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0RvcnRob2dvbmFsRWRnZVN0eWxlJTNCcm91bmRlZCUzRDAlM0JvcnRob2dvbmFsTG9vcCUzRDElM0JqZXR0eVNpemUlM0RhdXRvJTNCaHRtbCUzRDElM0JleGl0WCUzRDElM0JleGl0WSUzRDAuNSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZmlsbENvbG9yJTNEJTIzZGFlOGZjJTNCc3Ryb2tlQ29sb3IlM0QlMjM2YzhlYmYlM0JzdHJva2VXaWR0aCUzRDQlM0JlbnRyeVglM0QwJTNCZW50cnlZJTNEMC43NSUzQmVudHJ5RHglM0QwJTNCZW50cnlEeSUzRDAlM0IlMjIlMjBlZGdlJTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB0YXJnZXQlM0QlMjJyY3NuYUNULVoxNVRmUkVIREcyaC0xJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjM2MCUyMiUyMHklM0QlMjIzNTkuOTQxMTc2NDcwNTg4MyUyMiUyMGFzJTNEJTIydGFyZ2V0UG9pbnQlMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteFBvaW50JTIweCUzRCUyMjI4MCUyMiUyMHklM0QlMjIzNjAlMjIlMjBhcyUzRCUyMnNvdXJjZVBvaW50JTIyJTIwJTJGJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDJTJGbXhHZW9tZXRyeSUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtNzklMjIlMjB2YWx1ZSUzRCUyMiU1Q1VQU0VSVCUyMiUyMHN0eWxlJTNEJTIydGV4dCUzQmh0bWwlM0QxJTNCc3Ryb2tlQ29sb3IlM0Rub25lJTNCZmlsbENvbG9yJTNEbm9uZSUzQmFsaWduJTNEY2VudGVyJTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQndoaXRlU3BhY2UlM0R3cmFwJTNCcm91bmRlZCUzRDAlM0Jmb250U2l6ZSUzRDE4JTNCZm9udENvbG9yJTNEJTIzZDc4MTdkJTNCZm9udFN0eWxlJTNEMSUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjIyMDAlMjIlMjB5JTNEJTIyMjYwJTIyJTIwd2lkdGglM0QlMjI4MCUyMiUyMGhlaWdodCUzRCUyMjQwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtODAlMjIlMjB2YWx1ZSUzRCUyMiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTI2Z3QlM0IlNUNRVUVSWSUyNmx0JTNCJTJGZm9udCUyNmd0JTNCJTIyJTIwc3R5bGUlM0QlMjJ0ZXh0JTNCaHRtbCUzRDElM0JzdHJva2VDb2xvciUzRG5vbmUlM0JmaWxsQ29sb3IlM0Rub25lJTNCYWxpZ24lM0RjZW50ZXIlM0J2ZXJ0aWNhbEFsaWduJTNEbWlkZGxlJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0Jyb3VuZGVkJTNEMCUzQmZvbnRDb2xvciUzRCUyMzVjNzlhMyUzQmZvbnRTdHlsZSUzRDElMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214R2VvbWV0cnklMjB4JTNEJTIyMjAwJTIyJTIweSUzRCUyMjM0MCUyMiUyMHdpZHRoJTNEJTIyODAlMjIlMjBoZWlnaHQlM0QlMjI0MCUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMjAlMkYlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkZteENlbGwlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteENlbGwlMjBpZCUzRCUyMnJjc25hQ1QtWjE1VGZSRUhERzJoLTgyJTIyJTIwdmFsdWUlM0QlMjIlMjZsdCUzQnNwYW4lMjZndCUzQiUyNmx0JTNCZm9udCUyMHN0eWxlJTNEJTI2cXVvdCUzQmZvbnQtc2l6ZSUzQSUyMDE4cHglM0IlMjZxdW90JTNCJTIwY29sb3IlM0QlMjZxdW90JTNCJTIzZmZmZmZmJTI2cXVvdCUzQiUyNmd0JTNCS0RCLkFJJTI2bHQlM0IlMkZmb250JTI2Z3QlM0IlMjZsdCUzQiUyRnNwYW4lMjZndCUzQiUyMiUyMHN0eWxlJTNEJTIydGV4dCUzQmh0bWwlM0QxJTNCc3Ryb2tlQ29sb3IlM0Rub25lJTNCZmlsbENvbG9yJTNEbm9uZSUzQmFsaWduJTNEY2VudGVyJTNCdmVydGljYWxBbGlnbiUzRG1pZGRsZSUzQndoaXRlU3BhY2UlM0R3cmFwJTNCcm91bmRlZCUzRDAlM0Jmb250U3R5bGUlM0QwJTIyJTIwdmVydGV4JTNEJTIyMSUyMiUyMHBhcmVudCUzRCUyMjElMjIlM0UlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0NteEdlb21ldHJ5JTIweCUzRCUyMjExOTklMjIlMjB5JTNEJTIyMjg4JTIyJTIwd2lkdGglM0QlMjI2MCUyMiUyMGhlaWdodCUzRCUyMjMwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ214Q2VsbCUyMGlkJTNEJTIycmNzbmFDVC1aMTVUZlJFSERHMmgtODQlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHN0eWxlJTNEJTIyc2hhcGUlM0RpbWFnZSUzQnZlcnRpY2FsTGFiZWxQb3NpdGlvbiUzRGJvdHRvbSUzQmxhYmVsQmFja2dyb3VuZENvbG9yJTNEZGVmYXVsdCUzQnZlcnRpY2FsQWxpZ24lM0R0b3AlM0Jhc3BlY3QlM0RmaXhlZCUzQmltYWdlQXNwZWN0JTNEMCUzQmltYWdlJTNEaHR0cHMlM0ElMkYlMkZreC5jb20lMkZ3cC1jb250ZW50JTJGdGhlbWVzJTJGZXByZWZpeC1ib290c3RyYXAlMkZpbWclMkZrZGJhaS1sb2dvLnBuZyUzQiUyMiUyMHZlcnRleCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIxJTIyJTNFJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTNDbXhHZW9tZXRyeSUyMHglM0QlMjIxMTk2Ljg0MDAwMDAwMDAwMDElMjIlMjB5JTNEJTIyMzE5LjU1JTIyJTIwd2lkdGglM0QlMjI2NC4zMSUyMiUyMGhlaWdodCUzRCUyMjYwLjQ1JTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyMCUyRiUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRm14Q2VsbCUzRSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUzQyUyRnJvb3QlM0UlMEElMjAlMjAlMjAlMjAlM0MlMkZteEdyYXBoTW9kZWwlM0UlMEElMjAlMjAlM0MlMkZkaWFncmFtJTNFJTBBJTNDJTJGbXhmaWxlJTNFJTBB3Ih48QAAIABJREFUeF7snQm4HFW1tr/qPudkJBBmBSEMkTDPDsAVuF5HZpCAzOCAyDwpeBFO0MsoIAgqoBIQEIKKF0RFrwa8wFV+UUAhzJMMMhMg0xm6/med1E4qleru6qm6qvstnjzncHrX3mu/a1dX19dr7eWJAwIQgAAEIAABCEAAAhCAAAQgAAEIQAACEOhYAl7HzoyJQQACEIAABCAAAQhAAAIQgAAEIAABCEAAAkIAZBFAAAIQgAAEIAABCEAAAhCAAAQgAAEIQKCDCSAAdrBzmRoEIAABCEAAAhCAAAQgAAEIQAACEIAABBAAWQMQgAAEIAABCEAAAhCAAAQgAAEIQAACEOhgAgiAHexcpgYBCEAAAhCAAAQgAAEIQAACEIAABCAAAQRA1gAEIAABCEAAAhCAAAQgAAEIQAACEIAABDqYAAJgBzuXqUEAAhCAAAQgAAEIQAACEIAABCAAAQhAAAGQNQABCEAAAhCAAAQgAAEIQAACEIAABCAAgQ4mgADYwc5lahCAAAQgAAEIQAACEIAABCAAAQhAAAIQQABszRqYFHTrftr/PhMaKvx7ayygVwhAAAIQgAAEIAABCEAAAhCAAAQgAAEISEIArH8ZmLhn/3aQtH1I8AuLfkl6j4qBd0i6MxAM7XcOCEAAAhCAAAQgAAEIQAACEIAABCAAAQjUTQABMDk6E/YOCcQ+E/0qHU7UC4t7UWEwiVDozkcUTO4nWkIAAhCAAAQgAAEIQAACEIAABCAAAQiECCAAVl4OlUQ/J85dHXRhIp39rZH0XhdVaD8tqtBFGIatjIqC01nREIAABCAAAQhAAAIQgAAEIAABCEAAAhAoRwABMJ6MRfidEaT3uhZO3LP03P4Ul1Q1UdDZZUKkEyFTNI+hIAABCEAAAhCAAAQgAAEIQAACEIAABLJMAAFwSe+YsHdwEHlnr5i4ZsKa/cxSpJ1LH45LSXY2pylSZnmNYxsEIAABCEAAAhCAAAQgAAEIQAACEOhqAgiAC91vEX9XxQh/eRHRTBC0iEUTBN1hQqBFBLrIwK5e6EweAhCAAAQgAAEIQAACEIAABCAAAQh0K4FuFwBNODPhzxX1yHv0nNsz0KIYw4VKbF7TMhbF2K3XHPOGAAQgAAEIQAACEIAABCAAAQhAAAKpEuhmAdCi+yxqzo68C39xiyaugEknzjPVC4bBIAABCEAAAhCAAAQgAAEIQAACEIBA3gh0qwBoUX8uXdbSZHfMm+NqtLfTIh1rnD7NIQABCEAAAhCAAAQgAAEIQAACEIBA9xLoRgFwZig91oQ/EwC75TDR06IeXRGRZkQEhqsUu34dzzVjwD4b/M3GtsNVMXb/3y2+YJ4QgAAEIAABCEAAAhCAAAQgAAEIQCAVAt0kAIaj4ExsOrTLxD+3oFxqsEt/tr+bCGo8Kolwbn9B+2nCnvv/Zi1UN7bZYiJh1iovN2ue9AMBCEAAAhCAAAQgAAEIQAACEIAABFIl0E0CoIv8M2HJIv+6PeIsKgTGRQNaIRH7t32kqEh4kYYj+Fx0n3s9jrGLEnTRgdWERFfN+E6KmKT63sBgEIAABCAAAQhAAAIQgAAEIAABCHQIgW4RAJ341w37/dW6NOP2BzTRLVxF2Pp0Qp8JcXYYy2amT4dTiU1wjBMGnaB4tSQr4sIBAQhAAAIQgAAEIAABCEAAAhCAAAQgUIVANwiA4Wq/axH5V3ZFRPcHdKKfiW3NFvuSXphOFIyLQnSRgc6+pH3SDgIQgAAEIAABCEAAAhCAAAQgAAEIdBWBThcATTiy6D87uq3gRz0LObzPXxYj7Jx9B0ciFJtRzKQeXpwDAQhAAAIQgAAEIAABCEAAAhCAAAQyT6DTBcCng1RSK3AxPfPewMBaCLg9DE0MDFc1noava8FIWwhAAAIQgAAEIAABCEAAAhCAAAQ6nUAnC4Au9Zd9/zp7FbuoQKtqHBYCu7XKc2d7m9lBAAIQgAAEIAABCEAAAhCAAAQgUDOBThYA/YAGqb81L4tcnhAXEWjRgFlMZc4lYIyGAAQgAAEIQAACEIAABCAAAQhAIJ8E8iwAugIRjryL/rKfVkXW9v+ztF+LBOPoHgJOCLSIQDtsf0ATgV0F4e4hwUwhAAEIQAACEIAABCAAAQhAAAIQgICkrAuA4aIUawYpnibsJT2o+puUVOe1s7VjBWDsJ0VCOs+/zAgCEIAABCAAAQhAAAIQgAAEIACBhASyJgC66C0z30VwlZuKiTrhqC73+7PBCfb/FP5IuBA6tFk0GpCU4A51NNOCAAQgAAEIQAACEIAABCAAAQhAoDyBLAiAUZEmbK2JeFbEw4l69rv944BALQRcQRg7BxGwFnK0hQAEIAABCEAAAhCAAAQgAAEIQCD3BNolAJYT/VyqpoGleEPul1emJmCp45YSjAiYKbdgDAQgAAEIQAACEIAABCAAAQhAAAKtJpC2AGjCn6X2HhKaGPuztdrL9O8I2Lq7ChGQBQEBCEAAAhCAAAQgAAEIQAACEIBANxFISwA04c+El3ABD0vFJKW3m1ZbNubqREATnq1CNCnl2fALVkAAAhCAAAQgAAEIQAACEIAABCDQIgKtFgCjEX9E+7XIkXRbEwG3J6CJfzvWdCaNIQABCEAAAhCAAAQgAAEIQAACEIBAzgi0UgAM77lmWCi+kLPF0cHmmjBt+wHaT4sCpFp0BzubqUEAAhCAAAQgAAEIQAACEIAABLqdQKsEwHDVVaKsun2VZXP+4VTgtbJpIlZBAAIQgAAEIAABCEAAAhCAAAQgAIHGCTRbAIzu9UfUX+M+oofWEbAoQItUtTRg9gJsHWd6hgAEIAABCEAAAhCAAAQgAAEIQKCNBJotADpBhQILbXQqQycm4CJVLQXYUoE5IAABCEAAAhCAAAQgAAEIQAACEIBAxxFopgAYFv9Iqey4pdKRE7KI1aclmWDNmu1IFzMpCEAAAhCAAAQgAAEIQAACEIAABJolACL+sZbySsAEQBMCSQPOqwexGwIQgAAEIAABCEAAAhCAAAQgAIGKBJohALpiCjYQIgoLLm8E2Acwbx7DXghAAAIQgAAEIAABCEAAAhCAAARqItAMAdBFUNkearaXGgcE8kQAATBP3sJWCEAAAhCAAAQgAAEIQAACEIAABGom0KgA6IooWAVVi/7jgEDeCCAA5s1j2AsBCEAAAhCAAAQgAAEIQAACEIBATQQaFQDZP60m3DTOIAEEwAw6BZMgAAEIQAACEIAABCAAAQhAAAIQaB6BRgTA8N5/jfTTvNnQEwRqJ4CIXTszzoAABCAAAQhAAAIQgAAEIAABCEAgRwQaEe6ukmQioO37Z/v/cUAgjwT8wOhGroU8zhubIQABCEAAAhCAAAQgAAEIQAACEOgSAo2IHi51kuIfXbJYOnCaLooVEbsDncuUIAABCEAAAhCAAAQgAAEIQAACEFhIoBkCoBX/sCIgHBDIGwEXxYqInTfPYS8EIAABCEAAAhCAAAQgAAEIQAACiQkgACZGRcMOJODSf9eS9EwHzo8pQQACEIAABCAAAQhAAAIQgAAEIAABIgBZA11LgD0su9b1TBwCEIAABCAAAQhAAAIQgAAEINBdBBqJAOyXdIakaZLs97wf/y7pGkmrxUxkgaQnJF0u6TsVJvpLSTtJelbSvpL+FLQ9UNJlkpapAmlA0rmSTg/a7SfpUknLSrpC0hFlzt8g8MFHJU0MUrvN5sckXSzph6HzzpT0VUl9FWx5R9KRkiYnaGvduPY/zski2EGS7WFpB9F/OXEaZkIAAhCAAAQgAAEIQAACEIAABCBQH4FGBEAnoljqpIkoeT+cALiypCclmRhnR0HSewNhzUQ1E9OOipnshyTdIMnOL0q6SNIpQTsTBU+TNDb4f3t97eD3pyQNB78PBv1/L/h/+/k5SZaq+rSkXQNRLzy8iX8/kbSJpHclPSdpSNKqklaSNF/SBZK+HpzkBMDZkl4q47S5kr4paY1g/N6gnYmG60iaF0mZde1vy8kicAVsOkW8zgl2zIQABCAAAQhAAAIQgAAEIAABCECgHQQaEQAnBaKU2d0JhUCcADghiH6LRrNZZN4xgfh1kqQfRRx2jqQTgqi/zSU9Lmn7IDou6ls3lv39IEl/iHH++yXdEgiPL0haX5KJd2eXGXeWpM9Kejj0+vmBzWHx0AmA/yvpP2pcdC6S8Z+SNqzx3Kw0d5GrnSJcZ4UrdkAAAhCAAAQgAAEIQAACEIAABCCQUQKNCIA2pUMk2V5qnSCmVBMAbb4uxdeEud0iPr1bkgl/Z0k6IEgltlTb78b4PokAaFGGJio+Kul3IXHxI5H+fhBE6Vlk4ucjr5mIaFF5K0g6XNJNgYhodnWjABhO/e0E0TqjbyuYBQEIQAACEIAABCAAAQhAAAIQgECWCDQqANpcXDrldEmHZmlyNdqSRAB0opxFwH0gFN3n9uqztNqpkr4UsPiVpJ3rFABNbPyUJEsD/nmwP6GlEJsN14f6PDXYM9BE2OMk3V5l3t0aARgW/2yd2nrlgAAEIAABCEAAAhCAAAQgAAEIQAACHU+gGQJgOBU4z3uqJREA95b0/SANOJy6a9F3JirNCIp/WGSkFd94M1IMxC2oahGA7nXbe8+i+m6V9D9BqnW0GIgVFrE9AD8Z7Ff4qqQHg1Rk+3s4JdjGT1IExM6JS/HNawow4l/Hv5UxQQhAAAIQgAAEIAABCEAAAhCAAATKEWiGAGh9hwWWvEYCJhEA44Q7t1efVQ92Kb8myt0paSNJF4aKgSQVAMP7CbqUXxfpZxWG44qBfCFIybYxbXzzrRUXeUDS10KRgUmKgFgRlD1jFk0eBcBOWJu8g0EAAhCAAAQgAAEIQAACEIAABCAAgboJNEsANAPCkYB3BBFxlpaalyOJAGipvrann1XbdRGA5YQ5S939YiDARYuBVIoALCceuirDq5QpBhLmvLWkz0jaRdIUSVZExGz5dZftARhek8YnzxGqebmOsBMCEIAABCAAAQhAAAIQgAAEIACBjBFopgDoREDbE9CEFxP/rpZkVVfzcCQRAL8SzOcpSR8O9gB0hUHKzdHEwmgxkEoCoNtPcGIFaFbAI1oMJK65iYk3BunBVwaFQLptD0Bbi1aoxiIB7cjbuszDtYONEIAABCAAAQhAAAIQgAAEIAABCGSYQLMFQCcC2h54Z+RMcEkiAJrY92lJN0gyoc6KdJi4ZEKbFd8wsS98bClpg6ASb7gYSCUB0Ap87CtplqT7Iv2Nl/QJSQuCYiBWjOTHksaE9gqMLrfLgqIkZqftJ9htAqDjEScE2r6NFq3KAQEIQAACEIAABCAAAQhAAAIQgAAEOpZAKwTASoKLiS0WFZhF0aWaAHiupGMkzZV0ZCACfkvSsZL+Lima5mscXHqwVQc2sclScO0oJwDafoK3SVq9TJqvSw/eLCRC/lHSdpLulnRyUPzD+cCi3qxoyZqh/rpVAHRMnDhtgqAdpAV37NsbE4MABCAAAQhAAAIQgAAEIAABCEDACLRSAAwLLgeHUjDt75aGaSKgFcpwv7fbI06UW1mSFcEYCAwqSLICH8sFkXdW1OM/g6i/SoU+7HRXIGSypHD13nICYLVCH9anKxDyYhApaKnC1reJhkOSngsiES1acA1JRUm/D4p6vBOKADRR8qUK0H8eiGPhJnksAhI3RRP/8hil2u5rhPEhAAEIQAACEIAABCAAAQhAAAIQyCGBNARAh8WJLiYGuugr91oWBEEnypnYFz0s6u9RSZZO+8PgxS9LsqjA1wMh7k9l/B9XDKScAGjRfNtGxMJot3HFQOxvJkravoQmVJroZxWAXwkiBS0d28Q/O1wEYF+V9WrztJTh8NEpAmB4Tbr9AdkbMIdvYJgMAQhAAAIQgAAEIAABCEAAAhCAQHUCaQqAYWtMALT0VEubtUis6GFpmdOD6MDqs6AFBOonEI0GJCW4fpacCQEIQAACEIAABCAAAQhAAAIQgEAGCbRLADQUVh04HA1IBFYGF0gXmWRCtEUD2mFrca0umjtThQAEIAABCEAAAhCAAAQgAAEIQKCDCbRDALTIv5khpgh/HbzAcjY1iwa0tWk/LQLVCrdwQAACEIAABCAAAQhAAAIQgAAEIACBXBNIWwC0qD/bj84OE/5cqm+uIWJ8RxEw8e/pYEakA3eUa5kMBCAAAQhAAAIQgAAEIAABCECgOwmkJQCaqOKKLRhphJXuXG95mTUiYF48hZ0QgAAEIAABCEAAAhCAAAQgAAEIVCWQhgAYTvm1qD9Lq7yjqmU0gEB7Cbg9AVmz7fUDo0MAAhCAAAQgAAEIQAACEIAABCDQIIE0BEBLp7SIKhP9dmzQXk6HQJoEXMo6RUHSpM5YEIAABCAAAQhAAAIQgAAEIAABCDSVQKsFQCuoYBGAiH9NdRudpUQgXBSEtPWUoDMMBCAAAQhAAAIQgAAEIAABCEAAAs0l0EoBkOip5vqK3tpDwKWwEwXYHv6MCgEIQAACEIAABCAAAQhAAAIQgECDBFopAPqBbZb2y55/DTqK09tKwEWyspbb6gYGhwAEIAABCEAAAhCAAAQgAAEIQKAeAq0SAF0BBVJ/6/EK52SNAOs5ax7BHghAAAIQgAAEIAABCEAAAhCAAAQSE2iVAHiVJBNNrOLv9MTW0BAC2SRgewFaMRvSgLPpH6yCAAQgAAEIQAACEIAABCAAAQhAoAKBVgmALv23Vf3jVAikTcBVs14rEALTHp/xIAABCEAAAhCAAAQgAAEIQAACEIBAXQRaJdAhANblDk7KMAH2AcywczANAhCAAAQgAAEIQAACEIAABCAAgfIEEABZHRBIRoC09mScaAUBCEAAAhCAAAQgAAEIQAACEIBAxgggAGbMIZiTWQKkAGfWNRgGAQhAAAIQgAAEIAABCEAAAhCAQCUCrRIASZdk3XUaAdLaO82jzAcCEIAABCAAAQhAAAIQgAAEINAlBFolAPZLOiOoAGyVgDkgkGcCVtHaUoDvkLRjnieC7RCAAAQgAAEIQAACEIAABCAAAQh0H4FWCYCTJFnK5DOSrGoqBwTyTMBFtJqYPT3PE8F2CEAAAhCAAAQgAAEIQAACEIAABLqPQKsEQCPpRBMTTIgC7L611Skz3iFYyzafVl4vncKLeUAAAhCAAAQgAAEIQAACEIAABCCQMQKtFDRcFKBN2dImLX2SAwJ5IhBew9MkWWo7BwQgAAEIQAACEIAABCAAAQhAAAIQyBWBVgqABsLtBWipwCYC2k8OCOSFgItiZe+/vHgMOyEAAQhAAAIQgAAEIAABCEAAAhBYikCrBUCLoLLiCZZGiQjIAswLgei6ZR/LvHgOOyEAAQhAAAIQgAAEIAABCEAAAhBIXQC0AREBWXh5IhDe8w/ROk+ew1YIQAACEIAABCAAAQhAAAIQgAAEYgm0OgLQDRoVAa0oCHsCsiizRMDW6BmSDgmMIu03S97BFghAAAIQgAAEIAABCEAAAhCAAATqJpCWAGgGRkXAqymqULffOLF5BGxdmuhn4p8dFvXH2mweX3qCAAQgAAEIQAACEIAABCAAAQhAoM0E0hQAnQgYFVsoDtLmRdCFwzvR7+BAmHYIqPTbhYuBKUMAAhCAAAQgAAEIQAACEIAABDqdQNoCoONp+6xZcRATYoi46vRV1v752Tqzf7butg9+Oqvc+ptOler2OwoLIAABCEAAAhCAAAQgAAEIQAACEGg+gXYJgDYTUi+b789u79HWlFtbJvbZEY3yc4ws2s/EPxP+OCAAAQhAAAIQgAAEIAABCEAAAhCAQMcSaKcA6KCG9wa0v5koYwUYbB+2tAqFODGSKLDsLXXnG2fZmiETw4Kf+73cDFykn62ptNZV9mhiEQQgAAEIQAACEIAABCAAAQhAAAJdRyALAmA5IdCJgU4IbLZoE7cPnIlE7EmYncsgKg5Xs8z859bNncHvCH7VqPE6BCAAAQhAAAIQgAAEIAABCEAAAh1NIEsCYFgItEIh0dRNE3fcPxMF7ahFFAxHksXtA2f9uT0JEQHbv+zjqkY7cc9ZFxb83O/ttxwLIAABCEAAAhCAAAQgAAEIQAACEIBAhghkUQAMC4EmAjkh0O3pFsUXFYHiUkHjznUpoW4fODtvZkgEXCtDfuo2U8K+MJHXBFkOCEAAAhCAAAQgAAEIQAACEIAABCAAgToIZFkAjE7HVXG1nxbB5yq7Jp2221vw2SByMC56EBEwKc3WtTMfPB10j/jXOs70DAEIQAACEIAABCAAAQhAAAIQgECXEMiTAFjOJdFCEHGpoLWmCocjAUkHTu9isNTvqxD/0gPOSBCAAAQgAAEIQAACEIAABCAAAQh0PoFOEABb4aVoJKDtOdjfioHoc4RAtNgHkX8sDAhAAAIQgAAEIAABCEAAAhCAAAQg0CQCCIDlQbqiIWcETaYhAjZp1S3Zje3PaBGXdlj05qE1FndpiVF0CgEIQAACEIAABCAAAQhAAAIQgAAEOoUAAmB1T1rknxMBEaiq80raIiqwWtSfiX9U801KkHYQgAAEIAABCEAAAhCAAAQgAAEIQCABAQTABJCCFFW3L6CdYWKVRQTWsrdgspE6v1VU+LMZE13Z+X5nhhCAAAQgAAEIQAACEIAABCAAAQi0iQACYHLwUeHKVRU28Yqoteoc44Q/ov6qc6MFBCAAAQhAAAIQgAAEIAABCEAAAhBoiAACYO344oRAKxJiYhYRgUvzRPirfY1xBgQgAAEIQAACEIAABCAAAQhAAAIQaBoBBMD6UcYJWxYJaBGB0+vvtmPOPETS9pLspzvYQ7Fj3MtEIAABCEAAAhCAAAQgAAEIQAACEMgLAQTAxj1lQqAVCYkKXd0YFRgnihpht18iEZKNrzd6gAAEIAABCEAAAhCAAAQgAAEIQAACNRFAAKwJV8XGJn7tIOng4KdrbFFvnSwGOtHP5m2/R+dtVZQ5IAABCEAAAhCAAAQgAAEIQAACEIAABNpEAAGwNeDLRcK5wiF35jhN2M3N0ntN8AwfTuy0FGgKo7RmbdErBCAAAQhAAAIQgAAEIAABCEAAAhCoiQACYE24am5sYpmLDCwnmFlarAmCThyseZAWnuBst59x9tvQnR7h2EK8dA0BCEAAAhCAAAQgAAEIQAACEIAABFpPAAGw9YzDI5RLEw63CQuBJgw6kc3+3oqoOidSup82XjmxLyz42e+k96a7fhgNAhCAAAQgAAEIQAACEIAABCAAAQjUTAABsGZkTT0hHB3ofq82QFQIjIqCz4Y6WDPSWXiPvmj6bty4biwTIi1SkSIe1bzD6xCAAAQgAAEIQAACEIAABCAAAQhAIGMEEAAz5pBQyrBZZpF4doSj9JptsRP57KcTDxH7mk2Z/iAAAQhAAAIQgAAEIAABCEAAAhCAQJsIIAC2CXw9w/73Fw799qrjlzn2uTffHDn9mTfeuvrkW26NRuVFK/G6oaKRgkTz1eMEzoEABCAAAQhAAAIQgAAEIAABCEAAAjkjgACYI4e9MO30fsk/Y7HJ3rTVzjiTffhy5ENMhQAEIAABCEAAAhCAAAQgAAEIQAACaRNAAEybeAPjIQA2AI9TIQABCEAAAhCAAAQgAAEIQAACEIBAlxJAAMyR41/o//pV8nSIM3m4pEPXmPaN6TmaAqZCAAIQgAAEIAABCEAAAhCAAAQgAAEIpEwAATBl4I0MhwDYCD3OhQAEIAABCEAAAhCAAAQgAAEIQAAC3UkAATBHfkcAzJGzMBUCEIAABCAAAQhAAAIQgAAEIAABCGSEAAJgRhyRxAwEwCSUaAMBCEAAAhCAAAQgAAEIQAACEIAABCAQJoAAmKP1gACYI2dhKgQgAAEIQAACEIAABCAAAQhAAAIQyAgBBMCMOCKJGQiASSjRBgIQgAAEIAABCEAAAhCAAAQgAAEIQCBMAAEwR+sBATBHzsJUCEAAAhCAAAQgAAEIQAACEIAABCCQEQIIgBlxRBIzEACTUKINBCAAAQhAAAIQgAAEIAABCEAAAhCAQJgAAmCO1gMCYI6chakQgAAEIAABCEAAAhCAAAQgAAEIQCAjBBAAM+KIJGYgACahRBsIQAACEIAABCAAAQhAAAIQgAAEIACBMAEEwBytBwTAHDkLUyEAAQhAAAIQgAAEIAABCEAAAhCAQEYIIABmxBFJzEAATEKJNhCAAAQgAAEIQAACEIAABCAAAQhAAAJhAgiAOVoPCIA5chamQgACEIAABCAAAQhAAAIQgAAEIACBjBBAAMyII5KYgQCYhBJtIAABCEAAAhCAAAQgAAEIQAACEIAABMIEEABztB4QAHPkLEyFAAQgAAEIQAACEIAABCAAAQhAAAIZIYAAmBFHJDEDATAJJdpAAAIQgAAEIAABCEAAAhCAAAQgAAEIhAkgAOZoPSAA5shZmAoBCEAAAhCAAAQgAAEIQAACEIAABDJCAAEwI45IYgYCYBJKtIEABCAAAQhAAAIQgAAEIAABCEAAAhAIE0AAzNF6QADMkbMwFQIQgAAEIAABCEAAAhCAAAQgAAEIZIQAAmBGHJHEDATAJJRoAwEIQAACEIAABCAAAQhAAAIQgAAEIBAmgACYo/WAAJgjZ2EqBLJB4IxsmIEVKRDgfp4C5AwM0Z8BGzABAhCAAAQgAAEIZIXABEkrSlpO0ihJfQl+ujYLJA0E/6r9Pl/S68G/d7My+Vrt4IGhVmJtbI8A2Eb4DA2BfBIwARDBIJ++w2oIRAlM43rOzaLgfTc3rmrYUHzdMEI6gAAEILAUgTUkrSPpPYG4ZwKf/Vsh8v/2NxPz0j7mhcRAEwVfi/n/ZyU9JemFtI2rNB4CYJa8UcUWBMAcOQtTIZANAgiA2fADVkCgGQQQAJtBMZ0+TBQiAjsd1u0chWuynfQZGwIQyDOBMZLWDv0zsc/+3/1sh6jXKp4mFj4diIEmCEZ/n9NIoN67AAAgAElEQVSqgeP6RQBMk3aDYyEANgiQ0yHQfQQQALvP58y4cwkgNuTHt+6913zG0ZkEzMdck53pW2YFAQg0l8DykraStGXwz35fs7lD5Lo3EwXvi/x7s1UzQgBsFdkW9IsA2AKodAmBziYQjULhYbRz/e137tS6embh9ELEhvwsBScAmv94382P35Ja6u6tXJNJidEOAhDoFgIW2WcCnxP87Od6LZ68RdC5NNy4ffzc3+J+uj0Dw/sGlvt9bCgN2ebZyuORiCD4F0lzmzEgAmAzKKbUBwJgSqAZBgKdQyAaAcjDSuf4lpl0PgGu3/z6OBwByB5x+fVjOcsRADvPp8wIAhCon8Bakj4t6VPBz2ZoTK8GKbPPBPvr2R57bp8997v7aSm2aR/jQmKg7Uvo9iZ0v68iybhYWrP9rRnHryS5f5ZGXNfRDOfUNTAn1U4AAbB2ZpwBgS4ngIDQ5QuA6eeaANdvft2HAJhf3yWxHAEwCSXaQAACnUzgg4HYZ8KfRfnVc1jqa/jfk6H/f6ueDjN6zsTQXodOFAzvf1iPJvf/AjHwNkn2e+KjnsESd07D5hJAAGwuT3qDQBcQQEDoAiczxY4lwPWbX9ciEOXXd0ksx79JKNEGAhDoNAKrSvqypIMlWZXeWo77JVkaq+11Zz//Jmm4lg46tG0xsjfiFpI2q3GuFiV5vaRLJb1U7VwEwGqEMvQ6AmCGnIEpEMgHAQSEfPgJKyEQR4DrN7/rAoEov75LYjn+TUKJNhCAQKcQ2EDSkYH4l2ROtn9dWOyz3+cnOZE2IwRsf0FXMMX9NB8kOS4LhEDzQeyBAJgEY0baIABmxBGYAYH8EIgrAsJ+VPnxH5Z2NwEEwPz6H4Eov75LYjkp3kko0QYCEMg7gX8LRL99E0zkztD+dP9I0J4mtRHYUNJOQdr19glO/XEgBN4bbYsAmIBeVpogAGbFE9gBgdwQQADMjaswFAJLEUAAzO+icO+9VAHOrw8rWY4A2Jl+ZVYQgMBCAgVJ35Z0dAUgVnk3XJTiFeClRsAKjNjei04QrFSR+BJJx4YtQwBMzU+ND4QA2DhDeoBAlxFAQOgyhzPdjiLA9ZtfdyIQ5dd3SSzHv0ko0QYCEMgjgQ9IukpSuZTTxyVZmul3JQ3mcYIdZrOJtUcF/yaXmduDkr4gaSQaEAEwRysAATBHzsJUCGSDAAJCNvyAFRCohwDXbz3UsnGO8x0RgNnwR7OtQABsNlH6gwAEskBgW0m3SFo+xpg/B8KfpZZyZJOAFWcxMTCuKvPrknaW9CcEwGw6L9YqBMAcOQtTIZANAqQAZ8MPWAGBegggANZDLRvnIBBlww+tsoI9HltFln4hAIF2EbAKv7Z33woRA/4u6VRJt7XLMMatmcAekqZJ2jhy5qtWYRgBsGae7TsBAbB97BkZAjklgACYU8dhNgQkIQDmdxkgEOXXd0ksx79JKNEGAhDIE4EfSjosYrDtA3h8niaBrYsImM5n+/9ZRGD4+CECYI5WCQJgjpyFqRDIBgEEhGz4ASsgUA8Brt96qGXjHASibPihVVbg31aRpV8IQKAdBNaVZHv7hY+zJX2tHcYwZlMJnCvpK+EeEQCbyre1nSEAtpYvvUOgAwkgIHSgU5lS1xDg+s2vqxGI8uu7JJbj3ySUaAMBCOSFwD6SbggZ+ydJH86L8dhZlYDt32jFXUYOBMCqvLLTAAEwO77AEgjkhAACQk4chZkQiCHA9ZvfZcEegPn1XRLLEQCTUKINBCCQFwJW9feQkLEmBn42L8ZjZ1UCP5G0LwJgVU7Za4AAmD2fYBEEMk6APQAz7iDMg0AFAgiA+V0eVAHOr++SWI4AmIQSbSAAgbwQmC7JKsi64xlJa+XFeOysSuBpSZMQAKtyyl4DBMDs+QSLIJBxAgiAGXcQ5kEAAbAj1wARgB3p1kWTQgDsbP8yOwh0GwEr9nFsZNKHSjJhkCPfBHaQNDM8BVKAc+RQBMAcOQtTIZANAgiA2fADVkCgHgJEANZDLRvnuPde+zktGyZhRRMJIAA2ESZdQQACbScQfV4wgywK8GpJ9hpHPgksJf7ZNBAAc+RMBMAcOQtTIZANAggI2fADVkCgHgJcv/VQy8Y5CETZ8EOrrMC/rSJLvxCAQDsIxAmAzg6LArQvskwQ5MgHAUv3tT0d7XPkUgcCYD6cOGIlAmCOnIWpEMgGAQSEbPgBKyBQDwGu33qoZeMcBKJs+KFVVuDfVpGlXwhAoB0EKgmAZo+LBjQxECGwHR5KNmZF4c91gQCYDGYmWiEAZsINGAGBPBEgBThP3sJWCCxJAAEwvyuCPQDz67skluPfJJRoAwEI5IVA9HnhLUnLxRhv4t8dQWqw/eTIBoFqwt8S/kQAzIbTElmBAJgIE40gAIHFBBAAWQ0QyC8BBMD8+87Sptg/Kb9+LGc5AmDn+bSpM7p5n93X8Yqj7pb8VXx5F+9x/Y3HNXWASGc377fPtz35x0rey/7wgm33uPEXT5Ybr5a2SW1uRZ9Jx6ZdUwhEnxculmSiUWwKaTAiYmBT0NfdSTXRz3XsojYXfRZBAKybefonIgCmz5wRIZBzAggIOXcg5nc1Aa7f/LofgSi/vktiOSnASSh1cRsEwPICZBcviyxPvVzAgIlMV0myYhKVDicG3hmkCBMd2HxvO8HPeq4kzLqRzSdWydl8scTnSQTA5junZT0iALYMLR1DoFMJICB0qmeZVzcQ4PrNr5cRAPPruySWIwAmodTFbRAAEQBztvyrZQyZAGj3tWpCYFh8MuEJQbD+hRAW/A6WZP+f5DDhz7IPLPLPHQiASchlsQ0CYBa9gk0QyDSBajf0TBuPcRDocgIIgPldAAhE+fVdEsvxbxJKGW5z6/77fLzk6+e+/HELzVwydTYq4I20GEmxXdx25LcgzTeY6u27Xz/jk/Z7pfM9eXMKnvbc5bobfxtGVM0m1zbazlKMF9u35DwaaVsunbiWPjO8BDBtSQJJnxecKFWLIGUjucIhiILxKy8s9m1fg9DqeqtWpAUBMK9XPAJgXj2H3RBoG4GkN/S2GcjAEIBAWQIIgPldHO69137aN/EcnUUAATDH/vzZZz/z+aJXuDI6hbAwFxbw4qbqy3+loMK4xQLiwlZuv79q51vbYb/0hb1+8tMf2O9JbKrUbrGNiwXAcn3W0jYqVtbSZ46XSDeaXs/zgolW9jnlkDqBhUVB68JFC9rvnZhCbLzsn4uiNKHPjqRRlVHMTvQzVtV4IQDWuUjbfhoCYNtdgAEQyBuBem7oeZsj9kKgUwkgAObXswhE+fVdEsvxbxJKGWwTEeZGIvZm7L338qP6Cn/wfX9TSSN/C7cLi2C/2G/qbyR9wqbmed4DCwZK/95bGJwYigRc6vyw2Lfk+AvFupG+FkcSlrVpSTvLCX0L/z5Y6n1z8Zwqt23F+JWKkGRwWWDSwmJV4X3lai1g5YQtiwysV9CKE7hM5LJ/z4aiCJ1wGP3ZDj+6tNzwT/f7mhHBrxn21SL6hcdDAGwG/Xb0gQDYDuqMCYFcE2j0hp7ryWM8BHJOAAEwvw5EIMqv75JYjn+TUMpgGxfBVj6yrbwoZ9MJR8CFI/icMFhJFHQ4ojYMlIbXsIjEajb19Ixax6UtRysLLxYmF9pfS9tSoWfHZo+PAJjBxV/ZpGY+L7hIN/tpUW7hqLdWgSknBrq/R8c1QTHuMNEuekT33nPza9VcXL+usIrZmiTKr5I9CICt9lar+kcAbBVZ+oVAxxJAQOhY1zKxLiDA9ZtfJ1MEJL++S2I5AmASShlsc/N++3x78V5+SxvoRLihoQVPuqi8sNhWTkCsJABGxbrwHnomIha84kZJbDJrnQAYFh/t74vntbQAWK2tiqOObvb4CIAZXPzpCYBxI0VFwXrThnMHNqHBLtLR0qAbFfvihkQATOiIzDVDAMycSzAIAlkngICQdQ9hHwTKE+D6ze/qQADMr++SWI4AmIRSBtsgAC4tFiIAZnChpm9SMyMAk1rvIuvCe+KFhcKk/eSlnRP5winNLsqv1XNAAGw14Vb1380C4D/7T9vB971Jw97gHWv1n1MunLdV6OkXAqkTcGt+jWnfCJdxr9WOdtzQa7WR9hCAQDwBBMCUV0YTP2sgAKbsu5SHQwBMEXgTr8tFKbzlKvG6aUWr+O5x/Y3H2Wv1RAC6fQVd30lTgKOIw5GDaaQANzI+EYDpXSAL9QHv2dXOONPel+o9sva8EN1Tz/7fpefG7bdX77wbPS9uP8JwerFF8znhr9GxGjkfAbAReu08t5sFQOPu5j9c0qEIge1ciYydBoGn+0+Z1KueqwpeYdJQyZ9WpxCYtRt6GugYAwKdQgABsA2ebNJnDQSiNvguxSHxb4qwm/kMEFcExPpPmsJbpwC4qOLvEsVFKhQRibPJ/uYKe4QFzCUr8y5dBKRaW+s3WoSk0fERANO7QOx5oc/rfdqT94wvXV2nEJj354VoMQ7ngOj+fdX+HhdkFP1bFgS9WhcYAmCtxLLSvtsFQPsGsOB5M50/6hUCF1fR0qq2UW74JhX9ADD1ppvecOOV+zYwXBEsbq1E996wNpGKY4tOi36jF74BV1qHbtNhs7eaPdLiamCuz+rnLGwZZ19Wro9OtCO85uu8sSMgdOLCYE7dQoDrtw2ebtJnDQSiNvguxSGJ8EwRtg3VpOtyxOpKacDuM3uTIwBjaYWfD5LYZJ0sKfbFdVuu4m/ltq0YP+Ul0tXDPd9/2kzP80ZSaet8Xsi7ANjV/k8weQTABJAy2aTbBUBzSpSB/a0eIdAEL0/edgVPe+5y3Y2/jQphYUHNvVavABgVzsIh/GUW2u27Xz/jk1GbKi3K2gTAkZvDnPDcEQAzecmPGBW+qddxY0dAyK5rsQwC1Qhw/VYj1KLXm/BZwz1M2c9pLTKTbttHAAGwDeybcF0usjr6WTz6ubiZAqB9eb7w85t/bPA5bonP4M6oajaVa2cpxr68Rxb2v+SX/DHPHInblkuTrqXPNiyTrhzSRQGGJ1+jEIgA2NkrBwEwr/5FAFz6G8CwL2sRAt03aOX20Gi2ABi+IScR28LfCiZpX6sAGHBbJDQmGSMqZOb1Osqb3dFvvZ39CW/s3NDz5nDshcBiAgiAbVoN5d53zZyEnzUQiNrku5SGxb8pgQ4P04Trsg1WMyQE0iEQJ5AHgnOS1GCeF9JxU7tGQQBsF/lGx0UAXEiw3Buc45vkw3no26u74qLt6hEAY8/Zb59v2zdy7lu0eQOlvyzavyPY+8OlGUe+UVtKnIvrP25NVUpjDqcel+svkp68RDRio2uY8+sjEI0CDPdSRQjkhl4fcs6CQBYIIAC20QsNftZAIGqj71IYGv+mADluiAavyzZZzbAQaD2BuChAnhdazz0nIyAA5sRRS5mJALgQSaVvAMPQKgmB5fYBbGQPwFoFQLM1bn/AqOMr2YQAmNeruTa7k6z5MkIgAmBtqGkNgSwRQABsozeSvO+O3MfjC5MhELXRdykMzR6PKUCOG6LB67JNVjMsBNIhUE0gNyt4XkjHFxkbBQEwYw5JbM5SF7Wv6Vb2O3EHndVwN8nfLMmUygmBcfsANiIAVrYl0aa8sdF2SdJza00ZNlvLFfSoFgG48MNXYWSj2bhjuOTHVVBK4ip5Xv3nDmmo7nHX6j9nqXPtm7RERsc06lFP3ef6vhd7brGgr0qaUs2myI195CHlw5PW1DZrTdLkFVe8Y5eNNryz5JfueF//N600faIj6nPOhx/rJ5XrZykB8IVpp/kLL9qCt/jiLUX+Fv1/17JaO/e6a+/GKHdePe2iYyR6C2pjo8LudX7W6P/wpDXPOHjrrUbec20CvG921PvmyL115w2n3HH51M/csfT1GL4+w9df9LqNa1fueq31Oo5ev+HrNW/XYfQtoO7rso3vJd01dLVnhe6iUcNsfX/NGlov1dSTxvuePpOkj7jnhdB5tnetvc9xdAYBBMC8+jGJqp/XuaVhd1QIdBWv4sSzelKAK80hGulXqdpWdOxWCICV0omrCYAvTDu9X/LtjYQjwwTsxn7bww8/84Ubf7rDiTturxN2+EjIWm/aamecmfjG/sK0086QvFB7zodfLesn+p7h9692xjcTF0ZY+j2n1vUXHT8358cIgKfb1ze8/2b4vdc+a3zwoos23W/LLY/jfbed942WXvcjAuAJO/ybTtyx7PehGV6l3Wdaku2Buo9K62bMs0Lr2Da7Z3teuPWhh589fMZPt0cAbDbdzPSHAJgZV9RoCAJgjcDKNB/wB9eyiK+4fQCbHQFYroKWM80VI4kxtaYCHTVEAFbd0w8BsDnrLCu93PP0M5r18iv63Ic+gAC4iECtAlDWBNBGBbRGz6+VHwLgkqJdYn4IgFl5I63Rjgtm3iHPK3T5Fy8tFeCqeqTFXxwgAFb1QDYbuGeAbFrXOVYhAObPl8fdfItuuv8BZzgRgPlzYSWLEQDz6k8EwEY9t+RD18377L6OVxx1t+fpXwsGSv9uxTgWR9stTtl1o7r2kr9KOH221j36ys1iSeFt8fi19h/XPhJFWFEERABsdJ1l5/xfPjTrTvtGjwjARgW8ZgtYjQpw7T4/sYA1cjEs/SDQqP2Njp+b8xEAs/N2WoMlI+vLP3HH7fuzFQHY6HXX6Pm5ue7KvG8tYT8CYA1XRDaa1rb+smFzfq1AAMyT77xpu175o+Xue/75Y0NWIwDmyYXVbUUArM4omy2eO+PrhxQL8fuDZdPillqVeA9AqfxNP7oPYCQ1dwmhLCyi1SsAhiP+4vbgWyTeyZtT8LTnLtfd+NtmCIDmiXL2R71UTQCsuq9HA/tX+PLr3juv4BXqPjduXAuJr3cFl/xS3eeWHdfztpP8dZPZtGjNswfgosJBi/etZC+ujtqLq+olkeM9LCvsAVh12hluUGnfs8yZXe9nDdt7tf/QD37gjp02WJ89ADtvD8TIHoCZW7c1GJSr69HNq97rsgYuNG2EQNVnhUY67+BzG9lH3bAUC94Uybc9wxMc3rQBf2B6sA86RQMTEMtxEwTAHDsP0yVVK3O+GFL1b/ui+wBWSMld1G00rbcWgS4cRVjJmeE9+pLsARi2qZw9YWGvUmpyNQGQRZg+gQbWPFVE03cXI0KgWQS4fptFso5+GnjftdGoAlwH8xydQhXgNjmrweuyTVYzLATSIfB8/2kzPc+rsjHpEsKfMwwBMB0XtWsUBMB2kWfc5hCongpdXfhzloQEv1r23IuNDKxUWCM88yQiYw17+o10nUQAtHahfQ/HlbMXAbA567SZvTSw5hEQmukI+oJAugS4ftPlvcRoDbzvIgC20W8pDY0AmBLo6DANXpdtsnrJYcttKZTUOPc5veTrjj2uv/G4pOfRrrMJLIy69GaWn2Ws8IcA2NnLws0OAbA7/NyZs6z8zV9y4c/RidsH0F4rJ9JFq/la21oiAN24EZFtkbPiRLlmRQAumvN++3zbkz+yz0NcGjICYLaunWprPhS+H2c43+hly51YA4FaCCAA1kKriW2rve8mqAKOQNREf2SwK/zbBqc04bpsg9VLD9mIANjIuZmYPEa0jED56L+Kwh8CYMs8kqmOEQAz5Q6MqYlA/Dd/tQt/NQ1KYwi0kUC5NV9F+OOG3kafMTQEmkQAAbBJIGvtpgmfNRCIaoWer/b4tw3+asJ12QarEQAzAb3DjYiP/ksk/PG80OFrI5geAmB3+LnzZrn0N38If53nZWYUJfDCtK/7i/9W083cTkNAYElBIL8EuH7b4LsmfdZgD8A2+C7FIfFvirBtqCZdlylbvXC4JTN5vJcl/wDJu1byVwln4sTvE+697A8v2HaPG3/xZLXspGrnt2XyDJoKgSWj/2p+VjAbyRhKxVNtGwQBsG3oGbghAou/+UP4awgkJ+eGgFvzvu/fMaihQ4NKXbXYj4BQCy3aQiBbBLh+2+CPJn3WQCBqg+9SHBL/pgjbhmrSdZmq1eW2+wkb4QTAykUCF4qApULPjkWvcGV0ErY9UaE0NNMrjrrbRMWlJ7lYREwVAIOlQsBF/zXwrIAAmIqn2joIAmBb8TN4XQQWfvPXd0iCfXfq6p+TIJBFAvaNXp3Cn5sOAkIWHYtNEEhGgOs3GaemtWriZw0EoqZ5JZMd4d8U3dLE6zJFq5fcT9wJfVFRcJEAGOzPHd4LPBzx5/YgL7cH4M0Jz08VAIOlQuCFaaf3J9wWqJI9RACm4q22DYIA2Db0DAwBCEAgXQIICOnyZjQINJMA128zaabbFwJRurzTHg3/pk08h+MtTv1dMgLv1v33+XjJ1899+eMSFOMbmXk1ATCMJy7yMK6IYQ6RYnLrCCAAto5tFnpGAMyCF7ABAhCAQAoEuKGnAJkhINAiAgiALQKbQrcUiUgBchuHQABsI/y8DO0EwHBUn9keF8VXLV24mgCY9Py8sMPO1AnwvJA68lQHRABMFTeDQQACEGgfAW7o7WPPyBBolAACYKME23e+e++1n9PaZwYjt4gAAmCLwHZSt7UIgOFCIU4wLPb4e7o9/6oJgEnP7yS+zKWpBHheaCrOzHWGAJg5l2AQBCAAgdYQQEBoDVd6hUAaBLh+06DcmjGIAGwN16z0in+z4okM25E0BXhwsHTmqL7CH3zf3zScEpx0D8Bw9F+18zOMC9PaSwABsL38Wz06AmCrCdM/BCAAgYwQQEDIiCMwAwJ1EOD6rQNaRk5BIMqII1pkBv5tEdhO6jYs4Em6fffrZ3wyrghIWAB00X/GwYmC9nulCMBwn9XO7yS+zKWpBBAAm4ozc50hAGbOJRgEAQhAoDUEuKG3hiu9QiANAgiAaVBuzRikiLaGa1Z6RQDMiicybEe1ffnM9GgV4HLTcQJguQIfBa+4kSf/2GrnZxgXprWXAM8L7eXf6tERAFtNmP4hAAEIZIQAN/SMOAIzIFAHAQTAOqBl5BQEwIw4okVmIAC2CGwndrvE/nzy5gz5w8cVveI3JX+VcMpuuJ3kveyVhnZWsecHlhrsIgiNTySycJGImPT8TmTMnBomkIXnhTMlfVXS/0r6j8iMNpB0laStJf1D0hclfTpo3xdp60t6R9K9kv5L0h2h190Ycee8KemXko4Kzk8C9UOSbpC0pqTbJO0cc9K/S7om+PtBkv6QpOMmt0EAbDJQuoMABCCQVQIICFn1DHZBoDoBrt/qjLLaAoEoq55pjl34tzkc6QUCEMgGgSwLgCayXSFpI0n/T9Khkh6W5MS8+ZKeCWEcLWl1SWMlvRiIhNcGr7tzZkt6KXLOGpZ5H4iAuyZ0y6mSTpNUlPRWYNuvI+ciACaESTMIQAACEGicAAJC4wzpAQLtIsD12y7yjY+LQNQ4wyz3gH+z7B1sgwAEaiWQVQHwU5IulrSupN8HAtvzETHvCUkbRiZsAuDVknaU9KCkqZIeC4mGcVGGR0g6O4j+2y+IRKzG8Y+StpB0n6RtJV0pyfoJHwiA1SjyOgQgAAEINI0AAkLTUNIRBFInwPWbOvKmDYhA1DSUmeyIFO9MugWjIACBOglkUQDcTdIlklaT9ItA/LPUXne4aL44AdDauPTclSXZ/M6rIgA6oa4g6WBJv6vCchdJP5A0V9L3JH1d0guSLHrQxEZ3IADWuSg5DQIQgAAEaieAgFA7M86AQFYIcP1mxRO12+EepuzntNpP54yME0AAzLiDMA8CEKiJQNYEwOmSzpVk4p3tsfflmH35qgmABsDO3SeIBjykggBoewwag90lzZT0iQT0TPSzvQht38ADJP2fpHWCMSySEAEwAUSaQAACEIBAcwlk4Ybe3BnRGwS6hwACYH59jUCUX98lsRz/JqFEGwhAIC8EsvC84AS9R4I9/JaXNCDpAklfiwGZRAC8NEjJNVHPCouUKwLiur9T0mGSnqriuGUCwW+SpFMk2Tg/DKIUfxUpBkIEYF6uAuyEAAQg0AEEsnBD7wCMTAECbSGAANgW7E0ZtJJAdKCkyyTZA0S5wx56LPrh9MgDyz3BPkNx57mHj8Ey54bPsSqJcRUPG7Et2n89VRjLnRP3AOUe5OZIOknSj2KgPCTpfZKOlPTjyOsnBg9rtreUbfzuKkfaflHftKqrFfyDANiUy4ROIACBjBDIwvNCWJyzwh62v96/BZF/X5J0c4RVEgEwWlk4SRGQcKGRcu6xiES7R4dTfm3fQBMC7f5thUpcMRAEwIwscsyAAAQg0A0EEBC6wcvMsVMJcP3m17NJBEATnMKVC8OzNRHPBD1LMQo/FL0i6fOSbo2gcdEIthF6nHiYtOKhEwBrta2eKoy1nFNJAOyT9EBok/cwmjgB0DaHv0rSRyXNkzRL0qNBFcfNgxQu29PJok7KpW8jAOb32sRyCEBgaQJZEgAXhN5/bwmi6cKFPJz1SQTAyyV9QdIfIhGAcUVAbM9Au++uFwh5x1VYKJb2++kgxdiEPzvsPmwRhJsGVYtdMRAEQK44CEAAAhBIjQACQmqoGQgCTSfA9dt0pKl1mEQA/GdM5cI4A91DjkXHTQg2RbeIt/Bhext9W5InaXRMBGDSiodOAKzVtnqqMNZyTjUBcFjS9yUdFeESJwDeKGlvSZZmZlEcd0TO+S9JJ0h6SZI92P0pxikIgKldSgwEAQikQCBLAmD4fmWi3PWS1pB0XVCcoxYB8L8lWbEO+9Lnc1WKgFi/0ZThOPSuuMiaFfxiXyq5YiAIgCksYIaAAAQgAIGFBLJwQ8cXEIBAfQQQAOvjloWzKlUBrldkMzHLNhj/R0wasD0gWTSC7VtkUYDR9OE4ATCu4mG9ttVThbGWcyoJgPagZQ+HJgJaqq9t+u6OqAC4b5B+ba9H24bXjYmClhpsEYBXxiwoqjxn4SrDBghAoFkEsvC8EE3XdXOzPfZsOwyLDDw1+LLHXqsWAeiEuhUkfVXSd5skAJ4TfEn0clAwJOyDXkkflzQ2VDYtW3UAACAASURBVAwEAbBZq5R+IAABCECgKoEs3NCrGkkDCEAglgACYH4XRisEwLskTZS0WiQN+P2SLE1qSJI9kGyXQAAsV/Gw2QKgebBcFcZyAmDcOZUEQBM3/yXps5L+KsnaWrSkHVEBMEl0R5JVhwCYhBJtIACBvBDIwvNCOQHQGLpU4IeD7R7sZyUB0LZ6uFrSjpLuC90XKo1h98UZktYPtt+IRpQ7X94tycTFK4ICI1EfW3rwTpLs3vSRYOxrgkYHBenIaa+LJT5PWqoABwQgAAEIdCYBBITO9Cuz6g4CXL/59XOSFOBKRUBsY3H3oBB+YHk8qFD4naDwhRGyNFaLSLhJkqUk2abpcQVE4mhGKx4mKQISZ1slMa9cFcZazqkmAB4TPLhNiaQCRwVAK+zxsSCq7/AGlhcCYAPwOBUCEMgcgawLgC4V2KrumsBm6bXu3hi3n6xFhdt2GM9L+mKoIEe5IiA9QST5eElPh7Z/cPce237DosYt0jyu0EfYoa5AiO3layKifUGFAJi5JY9BEIAABDqTAAJCZ/qVWXUHAa7f/PrZ+c4eqqKFJJIU2rBiH1+TZNUIwwKgVbq1hw8rXLFtgMfSfz8h6ehAHIwTACsVAQlXPKzXtkpiXrkqjLWcU00A/I8gEuPsSCpwVAD8n4hA6lZYOeHTNoS3oivRAwEwv9cmlkMAAuXf09wrdt+y97k0j0rReWaHSwW2ADb7kqsQpPZaIajw4arc3yPJ9nQN7+MaLqoVPccixy3S/huhc6IC4Kck2VYSvwqKk8TxiRYDsS/nEADTXEmMBQEIQKCLCSAgdLHzmXruCXD95teFSSIAay20YelEewRVBl0asO1/d1uQ8rq9pJvLRAAmrXjYihTgclUYKwmA0XOSCIC2Wq6NpALbg9/7gsiNH0syAdD6sn39whGAlq51WrBvk/VjqdZ2HgJgfq9BLIcABJITyEIEYHJraVkrAVKAayVGewhAAAI5JYCAkFPHYTYEJHH95ncZtEoAtEi374XSgJ+RdFZQHfGIQOCKiwCMEwCNbjQ9txUCYLkqjJUEwOg5SQVAt4eTSwW2/Z/CAmDSPQB/EFSMRADM7zWI5RCAQHICCIDJWeWxJQJgHr2GzRCAAATqIMANvQ5onAKBjBBAAMyII+owoxVFQJyIt18g3Fk14BeDioO2z5ClAkdTXKulVLVaAKxUhbFaFeBw5cakAqC5yoRQlwo8V9KyoQhAx872ZvpSEDEZ595qAmAlgbeO5cIpEIAABNpKgOeFtuJv+eAIgC1HzAAQgAAEskGAG3o2/IAVEKiHAAJgPdSycU4rBUC3v5BVORwIKv9uGUy7FgEwruJhMyMAq1VhjBMAy51TiwBoKFwqsO0RZfs62ebtlgJsh1WG3F+SFVQ5TpIVBgkfnwv2vjJbykUAIgBm4zrDCghAoDkEeF5oDses9oIAmFXPYBcEIACBJhNIW0CoVkHSNuaN22TXpm0Prh9NMH/3MDe5zOa/cV3YQ7JtGGwPfJdJKld9s5J9LpLm1VB1zmrzDdvye0kXSLoqiEix/ixKpdzxleAh9I3QeNbWNiC2PlaRZBFBHynTgeNZ7gG2GupK/rAqaG8FVdVODaqsWX+OUaXUPjeuY2f/H344j9pVbR7Wj0XybBT41TaHHpL0uqTfBtVRH450aoUBTPwIs3HjhKu/RW1xNr8d8Uk1lvW+nvb1W6+dnLc0gSQpwPZ+Yym85Q7bv872qYuL4rM0YKtsaIf9bhGAdpQTAKNFQMpVPExSBMTGidpWTxXGWs6pVQB04uaGMQKgvf//RNIng4Ih9n71d0m2kfwmktYOWP5N0omS7ohxEAIgVz0EINBJBBAAO8mb5T+TjLxiH5Q5IAABCECgMwmkLSC4h8deSb8JHrzCZC2iYqtAqHkw2KzdiTNOgDGB7aUK7rCUrm9KWiPYo8nGcsd7JK0kyTbXfzP0d0v3MrHn3UAArMe+SgLgaElPBtE45Ux3D8x/DDbpt437d64wz19Kso3po+2+FVT7dJEtLvUv2lU14azaiq/kj/EB/6Kk+4OKaI+lLADaQ7ylPNpDvH2WMeHOHuLNx+tIsgd/S/2zaqomUlr1VHdUEgBNlDH2u8YAQgCstmp43RFIIgCW+yLC9WFfGtief3ECoEtltfVqArhVGbSjnAAYVyUx7suYpF9qRG1rVhVGe9+Oq9xYqwBoLI4J9kcslfmS4QuS7J+9V4wN+Nn9xb4osmhB+8Km3IEAyLUOAQh0EgEEwE7y5tJzIQKws/3L7CAAAQgsIpD2DT1JVNdUSd8JqixeKOmU0IOrRQC6B8t63FhN9GrEvkoCoNlaKYotPBcTo04PItQOkvSHmIm6fbNWDqIAzwvauNS/90sy4dTS/q4I9ryKdlONRTW+7vxy/nD7bI0KBAqLZkwzAtCl8b0c8DSBN3yEUwltr7TPSDKR0o5KAqC9PkfS1yRdEukTAbDaquF1RwCBqLPXAv7tbP8yOwh0G4G0nxe6jW+754sA2G4PMD4EIACBlAikfUNPIrDZ1E30suqMlqL5iYBFNcEpCbJqolcj9jVLAHTinkUrWlqyiYHRw4mEzwaRaE64clE/loJ6jaSTJD0XaeP6qsaiGs8k/rhb0jaSbpG0W4oCoEXtmChqkZxxQp2bm7G+TpJFSRlnixisJgBaBOqKgcBqYnU4fRgBsNqq4fWoAGjvwdPA0nEEEAA7zqVMCAJdTSDt54Wuht2GySMAtgE6Q0IAAhBoB4F2pQDbXJPs6xaOLksiOFVjWE30SioAxtnSLAHQ5nCDpH0qRDva+JbyZnv92Yb07jABa99AQDWRcIakVUMReGE+1VgkZVkpIjPKKa0IwP8ORM9KeyBWml+lCEBLpdw24Gr7hB0Q6ggBsNqq4XVHoFIRECjlnwACYP59yAwgAIHFBBAAO3s1IAB2tn+ZHQQgAIFFBLIoANrm7L8I9mkLp69mRQAsZ18zBcAvB9F/tjF/NA3YFfmwPbXC+/tZ2q9F2q0ZEvycEBYn0rVaAAxzckUI0hAAjYPtizhJ0sVBFGStl3wlAdBSiW3fQNv831KBLcrS7R+IAFgr6e5tjwDY2b5HAOxs/zI7CHQbAQTAzvY4AmBn+5fZQQACEFhEIO0berUIO0thPVnSpkHl2ENCe+AlrQJcqaptNdGrEfsaqQL8QkTos738/k+SVTKOpgGfI+mEoKCF7fHnDhMD7bXXgihAKyri/maFLw4NqvK69tVYVLtMKgmy5sejJX1QkqXMWhGCm1NKAXbFAJYL9o+8tNpEYl6vJgAeH7C0SMC/BNGYVjABAbAO2F16CgJgZzse/3a2f5kdBLqNQNrPC6nxnTFjRnHixP8ZP37FzSf29fX2bLnh563y+xKH7/uFp5765Y6DKs1+8+0XX/MW/OuND36w/13P86yIVCccCICd4EXmAAEIQCABgXZFAFaqbmn7sVlRhq9Lsgi2qGBVrQrwzyvsqVVN9EpS4bKcfY1UAbaIMtur7v+F5mtRc1+UZPvofST0d/v/rSWFC6TYy3FVgV003NoxxUCqsai2fJIIshbBeFHIH2lEAFYTcavNy16vJgB+PhBZLwsqCX8/EFsRAJPQpY0RQCDq7HWAfzvbv8wOAt1GIPcCoAl9K6308DLjl195lfFj3/MevzT4Pk+F1QrFvvd6XmElSRPmDsy+ZLP197896tz+/v7CPvtv8pVicdQeKpXe9AuFtzyv8PLwwJyXCvJeGPSHnp+34PUX333jsZd32OGit3MoDCIAdtsVzXwhAIGuJdAuAdCKM/xGkkVN2bGhpE0kvRUUbzg/xiNppgDXY18zU4Bt+ntLMmFpMBS9t4ukHwRFK8IRfa5wyCox+/25fQGtWMWHQ8ybJQDGCbJWhMTETLM1XCQjDQHwY5KsArCJzMeG0nONqYsOXC1mfYUjR5MIgNaFRRdadOPrwc/xkkwUtPmXq+DczDebtK/fZtre7X0hEHX2CsC/ne1fZgeBbiOQm88bJtZtur0mrDx+3OoTl5+8hoaHJhdVXEfF3rU9r7Cq5xXG+dJoX/5YTxrje96YgrxiaWjBb4oaOmTddfe0L+WXOh577Gdrq2f0z1XosSwl+fKHPN+fJ/vnFeZ60nz5pTklf/jl0tD8J31fTw0X/Mffnv3ss/Nmv/FSsThq9o479g9ldOEgAGbUMZgFAQhAoNkE0r6hV4rOMuHEIquGJV0QRACG55umAGjjRouUVLOv2QKg2fBHSSbuuWg/E5yOCNJPdw7BcWnBJlyWOywN+KuSvhs0aJYAWKkISNSWWgRAJ9ZNqFIw5j5JW0hyAl6lPQAtcvIsSSuHDLNqy/bNbz0CoI1lhVbsw6BVrv6xpEsQAJv9NtWR/SEQdaRbF00K/3a2f5kdBLqNQNrPCzXznTmzv2f0+HHbjV9m9cNG9U3YvrfQt1JJfrHkqVAqDRU8r+hJsn9LH6XhVxYsmL3PRlP2vdPzPL9/Zn/Pev9aYeVS6d15++9/6pt2wgx/RnHDJ3r27OsdO92XN7acgd6INljyPa84VBpa8LxUemDYH77r7bmv3/yBTT7/jPVf8+RafwICYOsZMwIEIACBTBBI+4ZeSQC0iC1L3/2opJcCMfDXIUrtFgCr2dcKAdAJe7af306S7pQ0JUgfPC/ExoTCf5P0T0kjH1QihxO5rDiGEw6zLgDafCx6cWKFvfzMJ/dKshRnixo9LZi3S4dOUgU4jkPSCEAbzgTZsyWNCqo374UAmIn3tqwbgUCUdQ81Zh/+bYwfZ0MAAtkikPbzQtnZP/jgdycWCitadszAhhvuPRgnqP3qV5eMGr/8u+tMXG6dLfp6x20hv7R+odg3yfO8ZUei//zh0Sr09Mr3ezxpQWl44JxXX3r4gu22+6plJnlXX33+xp5fOksF/7+fHD3v6mlTpw2YQX/6+5WrLDdmlW8We0Yf7Psl+Z4G5PvzC77m+Sq9XhoefMIrFP8xf/7rf33jnaf/eudvvBf7+/uX2ifQ9hR8Qk/0vv7nX49accXVR7/zzuyBzTc/1LKg2nUgALaLPONCAAIQSJlA2jf0avuzWYVbSxt9bxBRtXtMymotEWdRnNVEr0bsa4UA6FJ7RwcC138GFWh3lfRYMDmXFjyuglDm9hO0dF2XOlyNRbWlWI8gW0sEoI1v0X2bS7pK0udiDLJiIxYVWQzSfacHbb4QpJLbN72nSrL5lzsaFQCt32slfTZYq2OCwiekAFdbQd39ersEIiduWwXrU4LrJ+qJcKq8pfDbFg3h4xNB9esPBKn29po9ND0o6ZuSovsnuTGj41gqlH1pcV2FiO9KqyRsm43xvirRwmmuuHb5N805MhYEINA9BNJ+XihL9u8PXXtW36hl+0oqPeMVe/7pDy14ZcHQwOvjegpvPt8z550dJh2yICoK+r7v/frP/ctM7Flu3QnLTtqgp1Ra1+sZtaYKPatpePDFIQ1+a4N197T9x3XNNeeP8/3SmfJLx8vz7pV6jzjooBPud30+/syvP1waHv6cJw0MlwaeK0mz3p3z4qy5b7723I479s+PGm5i3x139I9dZa0PL+MPDixf0NCKvldYVaWhNQrFUWsXfE2ZPzj7+k3WP+DKNi4nBMA2wmdoCEAAAmkSSPuGXk1gs7lb+q9VkLVUYKuAaw9SdtQjOEVZVhO9GrGvFQKg2W/RbLavnSsGYimnJny5w4l7j0sKC4PhuZuwaiLa8qF04mosqq3DevxRqwDo9tgzccHWqqXXumODYI/E7QKh0EQLt6ektbF9APcP9uezNRQVAVcPBBAT6iySsJ4U4LAtvwiqNtvfolWdq7Gs9/W0r9967eS8pQm0SyAKi3E3BsVsota567Qv2MMzLADamjtRku13aZUS/xqcbEL9OhaREVynJi66w8a0yOWnJZnw6A7bs3TF4H/s+rEvJ9w1bO8vO8acE7b1SUl7Bn9AAOQqgwAEINA6Apn5vPHwYz87ra9vmW/4lmkrf87w0IIXC4WeZ+T7L3jSy74//Pzg4PxnVfCfe+Odl165/5XiG8d8+pgFUTS2V+DOO49ffn5hVN+LT6zy8tSpU+25Q1dfff5updLQFcPDpYGeQmG0CsWfzpkz5+Qjj5xmW+nIiomsvfabhS23/OJQnND429+ePHaF1TZZYUzf2PeoNLxmb9+4NeRrtUKhuMpQaeh9nrxJXqFnlYJX6B2ZgV+a8+6bz267xRZfeqB17qvaMwJgVUQ0gAAEINAZBNK+oScR2EyMsf3Utgoe/kzsshRYJzhVqwJsnilXCbia6NWIfY1UATab4yoB29+PkmSpwD2S5gb/b6mxdhgrSwveLEg/DQuD0RXq0oT/Jml7STcH6dbl0oYrcbTXGhEA7RvSZ8pcQuGH+nDataVQWGr4G5IsInKN4Kdxsyi/H0X6c6LeHkGE4POS/iLJPsCZUGGixrKSLArpjiACydaZHbWkALthTfA4XZJFACIAdsb7Yytn0U4BcF1J9jD0crC1gIsmdvO1a9sKBtmeovbFghMAD5P0LUmF4KdF+4WPrwTVzO29yqqaO8Hericb077QsWskfBwTVAm3azr6hY9tAxB3TpxfEABbuVrpGwIQ6HYCaT8vlOV934NXbjlhwhr/6y/8vLXoGNngz/NKpdKwFeJ4zVPhtYIVF/QKbwwOznlMQwMPDXmlJ+bOfub5556b/JoT/MJ9XHXVZasWCu/e7peGx73y6pvnTFx2/Md7+3o/WiiOPvqgg05wn70XnWKpxiuvXFpl9DLvXaMgb4pX6N2gWOiZVCj0LFeSJvoqreTJW8HzCrZNTOzmf/7w4N1z3351Z1KAu/0SY/4QgAAE0iGQ9g09icBmM3cPmstJuknSPiHBKQmZcDRXuH0zBMBy9lUSAE2MqnaUE42s0MQtktYLom22DHX05eAB2cQxq3jrUmDjxjKRzB6+TfCyYiAWOWP7LVY6ynG0cxoRAC2yqNwRTTk0dtMCe616r4kLtoGyRQrdJekbgUBcrj8TAK1SrwnKtp+gfUa0b3lfC3hayoWJoeGjHgHQzrfUR4vWfJEqwNWWe9e/3k4B0FJlTdiz95RoGrCLFrb3o8lBiq4TAO1LhG2CyFv7YiLucFG79kWDi8qtJABaHy6K+X5J7v3N3l8QALv+MgEABCCQEQJpPy+Unfajj16/ol8Ye1uhd4xtQ1HxCCp++L78eX6pNLfgFeZ5nregVBp6aWD+7P97/OXHzt5jx/6Rvff23nvv4k47feBy+UP7v/3OnIvfeOP5/lGjVvzQe1ZZ/kp53iivsNyHDz74CLs3jhx/nXX9h8ePXv6igvyVfK8wyveHx1pxEM8r2Gfc+GIjEWut0cCCd87sK4w9a/LkTy8VpVhtfk18nQjAJsKkKwhAAAJZJpCZG3qWIWEbBDJKgOs3o45JYFa7BUDbt9JSbv87kgZs0cYm7t0gaWpIAHR7jdrUrFr7rWXm6PYPtMgME97tC5xqAqDr24T5gyX9LviCAQEwwUKiCQQgAIEUCGTm88Y991w4ZvmV1/3PYs+o/6y3nO7IN8EDc7835f172BfpI8e11164x9Dg/B+XSv4/r/nxTR++4477R4TBiy/+2hnLTljm1EKh+JvRYybt5SIHLYX4swdu+Tuv2Gf3vfoOf3je0OC8XdefvOfv21wdGAGwPg9yFgQgAIHcEcjMDT135DAYAu0nwPXbfh/Ua0G7BUArKGR7+VklRasw7tKALcrPqmrbXqwWeWtbBFgEoEVlXyzpuZiiIFEGJvhZmv1ZkiwyupoAuLVtqyRphVARDxdhXIlvdN9OioDUuxo5DwIQgEBlAm3/vHHvveetuvXWJ78ybdo0Td1v40/19o6d4XuFsfU4ruj7jzz+0p+2/eQ2/batjBX+WMsfHr5WnjZ67pkX9vp6/3fsHjRy/Md/bLnsZ6fu8cuevuLmXmHUsaNHrz7diYB/+ct3piy7/Doz/UJx1Xrs8IcW/EnDA4eut95nHvnLXy7vne+/tfZ2W3/10Xr6avAcBMAGAXI6BCAAgbwQaPsNPS+gsBMCGSTA9ZtBpyQ0qd0C4JHB1go7hNKAXfqv7ZVpBUIuCwmAtRTwiabvVhMADVl0D78kRUDCe72yB2DChUczCEAAAnUQaOvnjcsvv7x3u48sd8y8OW99b6utDp/70OM/3bBYGHVVodhnXyDVdvilN4YH5x28/vv3tCJ7uvbaSyYMD889Vb6+9Mbrs684/sSzbZucJY7+/qM/sOYa7725WCj8y/d6Pn/wwSfaNhcjx0Ozbjiqb8zE8/2F+1MnPjzJLw0tuHRBb+GMTdbc+c2//e17k3pGLbP/xhsc8F+JO2leQwTA5rGkJwhAAAKZJtDWG3qmyWAcBLJPgOs3+z4qZ2EWBECrhG37gro0YCvwcXgQuWdFc8ICoCtG9GyCCMAHJdnepUkjAC3V1zZXt6I8Jkz+mBTg/C5sLIcABDqSQFs/b/zxj6eutOpq2/7k7TefOnyrrY55ctasq1fwist+s9A3xraaSHx48ocHB+Z8Z8zkLU5dy1trvqXxTpo07lOeShcNDAy8eN9fH9//+9+/ZtE+f+GOzz/3K8etvMrEaZ6861Qo9h900MlWhE4PPvjdiaPHT7rcKxQ/4yfc+8/O83x/9vDQvBMf/Nv106dOvWn474/85Et9PeO2WW/dXQ9KPKHmNUQAbB5LeoIABCCQaQJtvaFnmgzGQSD7BLh+s++jLAuAVgjE9vpzacBXSbJCO/sGBUDCAmAr9wDcOygsMi9UPIciIPld21gOAQh0HoG2ft64/6HpGy4zdtUZA4NzLln//XtdPmPG3sWNN9v388XesefLKyQptLfQI6XB/ysNzP/Seuvt9Xfbc++667615tDQ8IXDQ0MfnDdnwRGvvlG4rb+/3wrrLXWceOIXV5w8+b3fGztm9Lbyiic99dScGf39/UO+7xeeeObX/1Yqla7wir325Veiwy8N3e+Xho6asu5ud5seOOvxm2cWiqOG7rnz3p0PPbR/fqJOmtcIAbB5LOkJAhCAQKYJtPWGnmkyGAeB7BPg+s2+j7IsAFqknaVAbS/pwqBox/+TtLMkV7Hd7QFo87D9AbcNIvQOKTMx2zvwaEn/CPq1at3VUoBdFWB7CPpI0C8CYH7XNpZDAAKdR6CtnzceevLmj/YVxlxZGpr/zHqTdx8puvHYU7fZ/eIyFXo2SoS7NPSW5/snrrv2Ttd4njc0Y8YZffPmLHO4vMFz5rw777Jn//mv/zr33Ctml+vL933v0ktP32b0qL6r+3r7Xi70jDrswAOPG9mv79Zbvzh28nqfPL7QO+Z0LawCXPXwS0MzXn7ryaM+ssUxr/7+7v9cc433fuRxlYYeePmle3fbbrtpL1btoLkNEACby5PeIAABCGSWQFtv6JmlgmEQyAcBrt98+CnOyiykAJsAeKqkr0t6QtIkSd+UdF4ZAdAKgViacI+kSySdFpnYVyR9LXjdflobOyoJgMcExUZGBQVDrAqxHQiA+V3bWA4BCHQegbZ+3nj40ZsOKvaOPa9Q7F3h1RfunbTNNqe98Kc//dcqy6+06fdU7N2jGu6C5w37w8PXvzP8zolbTJ76qrW/7rrzJg8Nlu4cHBx85q3X3jr6pFMvuK9aPzvssMPoPffc7thlJ4zr9wo9Fw0Pr3jmoYceOhKt9/DD103uGT3xOyoUP24RfZX78ueUhuafPWXd3Uf2+5v12M+O7ukbf4k/PPTw3PmvHbDZhgcv2mOwmk1Neh0BsEkg6QYCEIBA1gm09YaedTjYB4GME+D6zbiDKpiXFQHwQ0Ea8JqSnpE0VZJFAcZFANp0bM1Z9eDxgWj412COmweVfwcC4e+U0NxNAJwi6WlJc0J/t6qJK1lSlj2LSTo49FqSIiBzA8HytkBknCzpSUlmQ/QIFwxJY9W0y79pzI0xIACB7iPQ1s8bD8268aSeUeO/Xij0TBhc8PaRG6y393ctIu+xJ245w+vpPVlesVI1YF+loUcGB+YcteGUqX8w111zzTXjPP9fPx4aHtpu3px5p3/56G9cLslP4tazzz5+3ZVWWP6Cnr7ej3he754HH3ziTHferMd++tmevvHn+fJsj92yh+f7Ty+YP/uIjdbf5/aZM/t73rP6Zr8r9I7ZwfdLT/vDA1+esu5uv0liSxPbIAA2ESZdQQACEMgygbbe0LMMBtsgkAMCXL85cFIZE9slEMVVy7U04J0k3SJpt8DecgKgvfwJSSdJ+oAkt/eSpfreG0QI3h6Zs425QQyHBYHoaHsPnht53QTAj1Zxr43pioaUG8N18UNJn09xubTLvylOkaEgAIEuItC2zxtWqGPfg7Y61/OKx3heoc8fnP+7F5//26d33LF/6OGHf7JT75jlLvO9gn2JFXt4fmmePzx01gv/vO8cO8f6W2utCV/yhxdcPDA0dOOjjz583AUX/OS1Wnx5wQWn7jpxuWUuLhSLb5RKPbsfdtiJtl2G7rrrK8usuOq25xV6xnxO8nvL9OkXSqW75rzzzGc23fSIV+6777L1J6yw7v/60gp+afgVf2DOKVOm7G33xTQPBMA0aTMWBCAAgTYSaNsNvY1zZmgIdAoBrt/8ehKBKL++S2I5/k1CiTYQgEBeCLTt88btt580bq33f/QyeQWrjut5fulfs995bsetNjn8kXvvPW/ViSttfLMvfUheIZalPzzw+16vtP/aa+/2sjW45przP1gaHr6hVBr2nn/h5b1OP/2Sqqm/0Y532WWXsZ/61Janjxs76nhPxR/NW7DsMYcffrgV1NKsWTe8vzh6ws3yinFffMn3/UFveMF3J6+z6/FWiOShWTcc3Tdm4rm+NEZ+6R1/aMFZ603e3W2Hkdb6QABMizTjQAACEGgzgbbd0Ns8b4aHQCcQ4PrNrxcRiPLruySW498klGgDAQjkhUDbPm/ctpHHpwAAIABJREFUc883V1t+lU2/Vyz27bIwR9efMzT3za9usMFnLxuJDtx/0+8Uesd8UfJsf9olDov+e3fOv7bffKNDbWsLXXXVRcsVtOCHhaK360v/eu3Ir3zl/B8E21DU7Ifzzz9p5eUmLHtbb1/v2oVi8eiDDjr5etfJAw9d/Zlx41a9oSQVl+rY99+ZO/+1/TZb/4BfWiGSzbbc+gav2LObL6/gyx/yhocuvf++uSdNnTp1uGaj6j8BAbB+dpwJAQhAIFcE2nZDzxUljIVANglw/WbTL0msQiBKQim/bfBvfn2H5RCAwNIE2vZ546HHf7phb884iwC0ivXy/eGSVxr++f33zdvXRLKHHpmxa9+oZX7ie4Ul9gG0KhyD898+Zf31PnOeRdrZnoHTp59/VMHz+2e//e7d//jHy3tdccUVI1F79R5f+tJ+H9h2m83uGi6V/lYsLrP/gQceaQW1LMqv+MgTN/+op3fcQTEbC77w7ON/2PBjHzt39oMPXrXxmPGrXOcXihs7G/zS0LVPPnLvkZ/+9LS367WrjvMQAOuAxikQgAAE8kigbTf0PMLCZghkjADXb8YcUoM5CEQ1wMphU/ybQ6dhMgQgUJZA2z5vPPjYzz4yqnfspZ5XWCSSqTT0wNx5r+6/2YaHPPSb3/Qvv+56H3qo5HlWWGrRURqa979D8wc+vdFGU9+11OHp07+1hafh75RKw2v/+d4HP/T9799gha8aPi6+6GtnTlx+wgm+vMvHjOk9berUE+ZZp//4x1Wr9o1d+R4VetYKDzK84O2r119v70Psb48++rPPq3fMWV6haAWxRkoH+8MDv3xr7qtf/sDGh43sK5jSgQCYEmiGgQAEINBuAm27obd74owPgQ4gwPWbXyciEOXXd0ksx79JKNEGAhDIC4G2fd545JGbdlPv6O8Uin3vc7BGimUMzT9lyvv3HCmWMeuxn11X7Bu/n3u9IL00f95bh244ZervPM8r/eAHFy7fWxw4veSXDnn37Tlf6xvz6pWHH95Y9J8b66L+45Ybt+pyN48ePXoNFXpOft/73r3Fio34vt/z0OM/P2BU77hv+563rLUvyPPnzn1150022P9X99xz4ZiVVnn/t/xiz+GStyhV2C8N3+Vr8Mgpa+/2YIqLAwEwRdgMBQEIQKCdBNp2Q2/npBkbAh1CgOs3v45EIMqv75JYjn+TUOriNsdfeOtqJb94j3ytIZXOuPiknc9sJY5jv/XL06XCNHl6ruANb3PRCbu8UG68WtomtbkVfSYdm3ZNIdC2zxuPPHnroZ5X+LZX6JmweCbeoD80//uPzfrlKbvscsXcBx+9cfcxo5azYiDy/dJ8f2jBxfPeffOczTc/9K3+/v6etdYav7v8oYvnzZ1/92tvzD7+tNMuKrv+a6W19957F7feetInVlpx4vcKXvEfw37f0YcddvxT1s/DD//4PcW+Zc8t9PTtb3v8eb7/8jNP3L/exz52yuwHHr5mozGjV7hUhZ6R1GZ3+P7ww6WhBUeuP3mPO2q1pYH2CIANwONUCEAAAnki0LYbep4gYSsEMkqA6zejjklgFgJRAkg5boJ/c+y8NExHACwvQKbBnzFqJtCWzxszZ/b3rLbm1serUDw7HCVn1vv+8B8G3n3tqI03PmjWzJnHLbf6mh9/TIXiin5p6K4FA7OP2njKfiMRdDNmnLfq/Hn6+dDw0MTZs9894Z57Hv/tTTfd1NQCG5dccvSEvr4VTh49atSRBa944Vtvjz7/mGOOWTBSpOSALXboKfRc7BeKGw0Ozr12g8l7HGh2zXrs53sWesdYavN7lhAAS4MvDg8uOGqD9fa6uWYv1X8CAmD97DgTAhCAQK4ItOWGnitCGAuB7BLg+s2ub6pZhkBUjVC+X8e/+fZfy61HAEQAbPkia+4Abfm8cdddX1lm+ZU/9PXevnEnL1VMwy+9WBoaOGLK5N1usak+/PjNNxaLo3YYHJr79Q0n7/Ujz/OG7O/Tp597UWl46LAFA4MXz5s3++wTTrhoZI++Zh/9px41ZfW1V720t7d3857eCZ/af/8j7rUxZs7sH/2e1TY9uad3zMlz57160CYbHPiL2x84f9waY9c9ubdv3Gkl349UCvbnlIYHj56yzi4j6c0pHQiAKYFmGAhAAALtJtCWG3q7J834EOgQAly/+XUkAlF+fZfEcvybhFKG2xx7/m0f9Dzvdl8a2bsrmjobFfAWTqUwLdzWfl+c5mv/59948Uk77Wu/VTrfk2b7vv+Ji0/e6c9hRNVscm2XaqeS3SsW2hdJAW6obZl04lr6zPASwLQlCbTl84YV0ugdvfw5hZ7RB0cFQM/3NTg45+tvvfbsBdtsc8K8B/4xfa9xY1bab/68OZ/daKOpA2b+9ddftt3Agtl3yvP+fNttv9v7ppv+0LTU35gF4l100akHLDdhmXMLPcVXxoxZa0urUmzt7r67f+UVVt70Cq/U8/n11tvltVlP/3pSQf53Pa/4qWg/ntUBGV5w6oP33XfR1KnTRuaRwoEAmAJkhoAABCCQBQJtuaFnYeLYAIEOIMD1m18nIhDl13dJLMe/SShltM0JF/xmr2G/9NOYB/NFwtySAt7SE/E875/y/QmLBMRFTRbu91ftfGte9AqfufDET/7Mfk9iU6V2i4YPiXbl+qylbVSsrKXPjLofs+IJtOXzxoOP/WztUT2jL/MKPZ+MM6s0PHBrr/yj1lln1+csWnDcuLVX3XzzLz1ubWfMuHD5+fOH/nd4aGiVN958+/ATTzxn5Fpq8VG8/Hv9V4weM+ogXz3nrrnmVv077rjjSCTi9bd+a8XP7nziG1aUZNasm7Ypjhp3swrFlWPeZ1QanHvhO7MfPXOrrU6Z3WJ7XfcIgCmBZhgIQAAC7SbQlht6uyfN+BDoEAJcv/l1JAJRfn2XxHL8m4RSBtssKcwtjNg7+pJfTSgO6le+r21dFF+4XVgEO/Zbt90gefvY1DxPdw/36tM9Q8PLLI4EXNhnVAB0Yt8Sfw/EOusren6cTUv8rZzQF/x9qKf4zqI5VWnbivErFSHJ4LLAJKktnzeeeurXmwx53tXyvM3inOCVBv81NDyw5/qT9/yThdi6NpdffvnY0aNnT/NUOuatt97+4THHnvXltJx4/PEHrLvJxhv83PO8ScWeMXsdeOBxvwuP/Ze/XN47frlVjugpjrbqwLL/okdpcN71Q4Nvn7zBBge+lJLdCIApgWYYCEAAAu0m0JYbersnzfgQ6BACXL/5dSQCUX59l8Ry/JuEUgbbuAi2spFtFUQ5m044Ai4cweeEwUqioMMRtaFYKK5uEYnVbCoNF1ZfnLa8ZGXhRcJkYH8tbT2/90PNHh8BMIOLv7JJbfm8MWvWTyb5xb7DCj19y5aGB4c9rzAsrzBU9HpGfi8UiqU5s5+/ceOND3nU87xFAuA111y4i18auHR4aPiN3/7Pn3e64YZbXkyT+Flnnfj/2TsTOKfKq/+f89zMxqaCuNQNFVEUu+nfWu2itlYLtS4wC1YrvLba1iqCDE7QykwXMjoIota+tVVwqcxkAFsVW1urtG9r3Vq1iiJYF9QqKrIzS3Lv+X+ezNyZm5BMksl6b35RPjOT+zznOed77k1ufjnP85zzif1H/YZZ/Y2V8b1vf7v+DXt8LQAO3+sTp5dx2XH6OaV8Ua6JhLnbDK/zccXvDz/8dFQA5jNxGAsEQAAESoBAQd7QS4ArQgSBfBDA9ZsPyrkZAwJRbrgWi1Xkt1gykaYfMxY8dF3fWn5x+toinDKsd/qr8vrFtkQC4sACYIxY51h/UIuIpoSPScUn7a4tADrFR/18X1xxBMCkbS2+ONvjQwBM88QsfPOC3G/oXYA7OkYOqaoyrB07fNZHH5VbQ4e+ab38Mls0j6xGbtSiX9TygL/+dWCsz6duNMOhL328ecfk+vrmxwqAz1i8aO6NI0eNuNi0aKHIvoHp06d3FsCPVIdEBWCqpNAOBEAABFxOoCBv6C5nBvdBoFgI4Potlkyk7wcEovSZuakH8uumbDl8hQAYRyyEAOjSszmrbrvmfuPee28+MBzedZuheOJTT7/41VtvvXd1VkmkaOzmxdc8MmKP4ceLqMa33tr188bGRivFroVoBgGwENQxZmYEpjQsO8VHxhgic3Vr89Q3M7OG3iBQ/ATsc761uWZpBt665g09gxjRFQS8SgDXb54zm8V7DQhEec5dnodDfvMIPIvXZd8U3kQ78dphxe7iqzf20McGVwHYvztwPBuJpgDHIo7efTf3U4AzGR8VgPm7QOoagtOy8Pm4IPcbTzzRONI0yk/ykTFKlK9Swl0VoriivGxYJRu+CrKsIaHu7Y+8c8Jhj9Zwz467+nH3kgXnWRJe3B3qNv/7njW2sbExshFHnh7c0jL7f/bbd/SvLKHfH3zwCZNPPfXUvuq/l14KDiurGnI7G74vmmZ3iIhDRBQipu7u0I5uRUZIxPxjmXTfNn78RZvy5DMEwDyBxjBZJlDd0LqEiacp4ulZeKHLsncwBwLZJVDXsGyMkLGEmMawUNMghcCCvKFnlwSsgUDJEsD1W4DUZ+leAwJRAXKXxyGR3zzC1kNl6bqkeJuAaPupTuEdnADYv+Nv1OYiA2wiEs8n/Zy9sYdTwIzamTfOJiDJ2mq7sZuQZDo+BMD8XSBaABSmeaw307DCSwdZKFOQ+401r/1urI/V/7JR/pX4xCQc6tw2ub315YdiKux46dKWhUzmZTt37Pr108/+ddbSpavzMgX3iisunHDcZ495XEQ6WFVMueiiWU87fX/44csrDhv31XrDV/mTqLnLvY2YSMKhnYH3u94LnDrhsh15OlMgAOYJNIbJMgH9DaAi9bhtNptCoP2GzERv6x29brli4rZY96N35HIejf5mTx+Jt3uXs4fzWzx7bY7E9mM9ibdrWXzY9mLEOp6oGwTa3ed4O5PhDTzLJ3Ga5pznPDO/qd/cW+dX6w8eqT4K8oaeqnNoBwIgMCABXL8FOEGydK8BgagAucvjkMhvHmHrobJ0XUa8HmgacNzdeinTNQDjw4reRCTx2oTOdtH38nHsJtrxN54LjrapMNEm0hk/z6dIyQ6nCwYsUpFNKAb5WUF3jb3f0K9xTbmGumbNr0ca5aN/apRVfj+eWEZW+HUh67wjDzvrBb1e4KhR+wz/5Cd/sFn7dVfwFwfQzi0rlMFHvbXhvUuvvXZxW679nT//8tGj9hp1c0VlxbnE5XOmTbvqZnvMZ/5952E7Nm3Y8Je/kDW59qiJFRUjlpMyKnb7FG+Fd5IZunLZb56/M4/Thu33rIg7u+9LnGtysA8CGRCwvwF0msiGENgnvhEdpNg8KVb4SnXNkMX1k57SvhWLANh7lW/QMYV9xvZ43xzaLPt2ENPfMLKasvCqM1dkkCp0zRKB2obg40Jyim0uzTd3CAhZygPMgEABCOD6LQB0PWQW7jUgEBUod3kaFvnNE2jnMFm4LvvMRU+njXwg3ioiZ9j38dmdAmzp13K9H2hEUEk0/TiZT333645NRHqekzYieTli3yHq6SOxNtNpm6qfA9kswGlSkkPqKkCLZMkgPyvobgW539Ci3icO+swMVuUBUqosNnlWuPuBEJk/PHbsOW8/8URg7KjR46e88NxzC2tqmrp126VLF3yJJLwyFAq9umVrx6X19fNfytUJcNxxx5V9538mXjpk6JB5RGp11ZBDv11TU9Ohx3v+ldZx5Ybvyl3bNvmPP/7Sra++/uCnSDjIRtm43fwR8z+WGfrhUWPP/kOufI1jFxWAeYSNobJMIPYbQKf5TIVAW+SLFb+SftvV92pLEaFNi4dFJQBG/Ov59tJ5I+CsDoy+Qdi9OjDLaYS5NAgkOudTFAIL8oaeRnhoCgIgkJgArt8CnR1ZuNeAQFSg3OVpWOQ3T6Cdw2ThuiyA1xgSBHJPwFkF6Bwtxc8KukvB7jfWrl9ZrXxVi4nV/lG+60+v4a75oRHDAxP2OXXHv19ZNm1IxZ7XdHRuufLYo6eu0m1FhO+558Z6sUKNHZ1dv3zyyeebli797ZZcEG9pmf25PfcYcUtZecWeRGXnTps2a40e5/GXfj7sgKpDrlXKuGTLpte+fPzxl7/49It3HjS8atRin6/y3N0qG63wX8NW12VHjz0vZ2JlnPhRAZiLkwI280cg3jeA2RAC+4W+/lL/3aflRotj0d8Q9gttmQuAyUW4ZGMkXuekf5qBLXb2Vf/FfHOYv6xipIEIxFYBpvHmXrA3dGQUBEAgYwK4fjNGOHgDGd5rQCAaPHo39ER+C5SlDK/LAnmNYUEg9wRiqwDT+KxQUAHwlfUrP2/4qm4lVp+NpiQ7wuHOy8YffvY9zCxr1//2N0ZZZZ2Y4d/5mGcedtikt3T7O++8ebRPdd4dCnd/urOr87LLLvvpymzTnj//slF77TW6saqy4rvKKP/e669vv9feeGTt+t99Uxllt7IyDgp37/je+HGTf/nII7OHHnr4FxvYV3ltrAAoZqi1a+eGH9hTmbPtawJ7EADzBBrD5IjAQN8AZiIExlsHMJXKOKcQZ1fVaT/s6ba6NH7x7El1Tt+SrwGYOwEwSjhk2iAiC5n4ph7/oncVy1EKYTZNAqmc8wm+5YOAkCZrNAeBIiKA67eAyUjldVe7l2D2AQSiAuYuD0Mjv3mAHG+IDK/LAnmNYUEg9wQSVQE6Rx6gIrBg9xsvvPCrA6uG7fcLNsq/ESWWWeFXTLP7B+OPOHe1iKh1r696i42yA5moOxTuvHbj28/dcuqpjXrjD777jgUnky8c7OzsWrt909bvXTV34bpsEW9sbFQjhnaePXLvPe5RyreSle/qCy+c+Z62v379/YdbhnErq4oz9d9m986V48edNzly7PWHLhA2tLC5h+2LiNVlWeGF4w8/6xpdwJgtH1OwAwEwBUhF20Rf3KR804rWwTw5JiJni8inUxku1anB8dYBTLTbV+y4fWsExtl9a3ACYPzInOtxpL5pyO5r+sWb1uycEjwQV33z5VO+vjXpdmtryZup5CVemzCZg+7rIxp033g7ZkWutUE+wkSD7usjI25fk6yrmfioZC7FvLnPG7rH6MYhe4ymfQ+ZQMNHfWL1IUd//i8+Vb763p+euzqZLfv4Bdfef0rY6u7LOfqDH86fvFw/u92Q1zS0RW4Ylepfw9myem4i7edi/7av42Tt7ON2+0T2MmkX2zfV16BCtWPmcwZ5r9E4+uCj54397Ncir7naf7xueup1M/Jh6qCjTlz9+XNmro69Hp1/O6+/VNolul7TvY5jr1/nde226zD2+s/guizUS0nJjZv0s0LJEUkh4Aw+P/VZZ/UFS8yLk40WRwgsmAD48MM3V4w98vCb2DC+K8SG7buI+fuuUMcPPzlu8utPPLvw2H32nvCCRRLZv0LCXa+xJRffd9/Zf2tsJOuOO64fXlbGM0ms+k0fb1v0+uvbf3bLLbd0JeOQyvGf/GT2ofuOHt5eXlkxRCnjh9/+dr3ekFT0br9jxp5SX14xvNESifjNVuh9MtWYI46Y2LV+/covi1FxKynfhL6YLPMDCXc2HDXuvL71GlPxIQttsAZgFiAWzMRA5b0Fc8olA6ciBOqpsEx8pr0QsDcEwPjVhM5NPxIt9BsvtXVz2xsty17Q2CXJL0E39Zv7tk3vWhvffOmwUNcuGv/5c/ooKEVNrfNrU95NuKahLeqNI/P+qimd3Yx3Hx/93cSvbm5bo2VF1pexH43B5tqUd5eL7Z/u+efi/rvdkNfNbaMYliX46lbcIet7jd/d+r1PHf6Zr1559MmRQoDII93zFq+7mb3v5Pi6jwiAx3xhCh3zheriPiHhXc/1RzydyFwd7wtfIMo+AXxWyD7TXFh0CIH6i0Tn5wJ9j5by54RMfXvl1RVXGeVDfmRXyzGJaYY6f7l+6/P1Zx3fuOulV9tmVlTsuTCqZE6sB7ZtWnPx8cfP/kiPf8891x8pptwYNs0Ttm3eeeGVs+c/kqlfRFR2263XLR42fOhUS2jBkCGHLrQ3/lj72gOnKWXcR8q3b9/7PLF8vHn95074zGXP/OO5X4wZOeKgW9kom2QfZ7HW7di58X8+M2Ha37PgWzomUAGYDq1iawsBMPOMKLIOTXQDELsOYCIBUD9vkTXTLKOJt1wxcVvsGnrOHXcLVwE48HTeRDucJSOMN/VkhIrv+Mf/fY1GfmIsPoj2fRB3t4Cob8oyEdDS7x8t+qcrZEAAjBZA0+C3mwBY29C6pxDPKL5XGXjkJLDmb+3ErKiUBcAcC3BJT7gcjw8BMGkGirPBQJ8BitNjd3qFzwruyluoa9eW5x+9a883XuybHJRXAfDldSsmlZUNvU2YD46Qs8JbrHDXvKPGnXez/vPV9fc/zGVDvh5NVcJW986mo8ZN/ql+Xk/VPfTQoWeRmDebYfPjPz/+z7N+85uV72SSiebm2efvt++o2xWr1WUVvu9PnXrV29reX/86d//9DvzC70gZ/89pX5cndndsmnvM+PMD69c/XGEZVgsr3/eJ2BdpJ/LUho3/PPurJ16zMRO/BtEXFYCDgFY0XSAADj4VSiX/0N+/Np/8Qa/bl2gNQGf1HDGtIaFjtGfx1gCMN7U2V2sA7j4tOLEICAFw8OeS23qKZRKrvqp6VKKk8FrgzHGcG9k0Bbjdqmbz3D/TCjwIgM6quzQEvMhplIEQsXsFoL9tjCV0kdteg0rJ3957DZrwxZp5xSQAZir8p99/0MJ3ptdNPvpDAHTZRZ3KZwCXhVTU7kIALOr0RDmnqwDXPvXA8y88dm//VKGe6r+UZ2pkGu2TT95wxN77HLvCUurYyOdpS14LhXd+/+hxkx994onGkfvsf+JLFnPULsG6nRJrc0fnlvOOHT81olwGgwurOjvDjZZpzdi1c9d9P/jhj/V06EGttTdjxgVHfvpTx/xOKbWvlFWcPe1bV/6fbWv9+t/eTmVV3xHqX47FZmB273p0/LhzT9d/v/zq8suM8qE/ZlYjicSUcPfyF/51z7dqatrNTJml2R8VgGkCK6rmsQKgXbpbVE7mwZm01gBM48N+7DqA0ZV8OrD+6bRRImBvzPauuvrP6OOJdxa2+yTb1TcWa6L2sSKg0yenjcEKgMnW9TAt85DBngKK1KDXziMe/Lp7IrLbuPraGmwcJINfj9AiK+64TPwFIuov40vDuV3bPqLNG98kywxhDUCsxYW1yNyzBubuawBe3boHMV/Zd/kzbxGxnmeh54l5SxovCwVrGm99tII5k2RgEU59veHoew2sAejttWOj1gAs1vM3Fb/cdD3a8WRwXaaCBG2yQCDZZ4UsDOE5E5l8fuqHwWOZSH9eSPqIaAhCTa3NNUv1kgaFnAL87LO/LBux9yEPE/FXIvU0Ik99+N6zk0866dp316y5+7SyIaMfIFZD4wXFYq15/53nv/jFL/o36+P33nvzCCvc8TeLzEM+/HDrZfX119+bFEZMg1NOOcV3ft1XlpZX+OpY+ZreeGPnzxobGy3d7KV1y6dWlA37X2EeEd8f+eC9t/8y4UtfCnz4yvqVXzZ8Q35FzEeQ3gAktPMnR42b8rN0/clCewiAWYBYMBOxAqCQLG1vrpteMIcKMHAquxxptwb7bV+idQCThRpb6de3MchAHXs3DVk066x3U97UI4WNRqLEPccYTlcGKwAm44Dj2SeQ6jlPzO+RSNQ3ZB9ueJnWPvUAvfef57RjeS3pzz4JWASBkiIQ94a8tiH4uJBEbcSkb+QtsVYbpP7SezNfUqByEWyqr7sJ7jWwS2wuklI8NpHfAuUiw+uyQF5jWBDID4Faf/CNeEUNztFjhD/7UOz9Rl4rALUTa9etWKTKh1/GZCkRq+2IMV+/gJll7boVP1JlQ64lVuUJKHZJaNfP/7P+sbkTJ/Zs/HHvvbedaIa3/Mmy6JVX1r524Q033Plqqhmorq42Tjrx8Av33GtEgJXx5pAhh365pqamW/d//vnbxw0dfsBvyPAdF6/6T7dhke3dXdtqjjmq5g9PP33DfnvtPeF+UcaJitT2zo6PqyeMr83G2oSphmO3gwCYLrFiag8BkKi6oXUJEyfcCXmwwp+d537hrr9qLyUxj6J3201N0EtcGZjwvEtBANR9o3f63X0jEAiAxXRlD+xLsnNeSH7PxHoaes/aGb2Pze+/sebZR351zOb3/mM/BQHQPWmHpyAQVwBMthRI38wAK7wUC94P/iRK9rqb5F4DAtHg0buhJ/JboCxleF0WyGsMCwK5J5DKvYEp5vTlzT3TZWMeBa0A1L689Gr7t8srRvwvk0i4a8ePxh85ZaGuDBy+5/5B9pV/k4hVIoos8lY4tGvWi8+Hf1dTUxOZXnvXXS0/sszwVaHu7qX/fX9zY2PjTSnNkvjxj2ce+4n9R93s8/nG+coqz7nggiuf0faee27JnkOGj/qx8lXoqb9VCTMqVpeEu64/8ohz5okIr/vPg3eR4TtfCX+84f1/fuYrJ137bu7PhoHzG9lKGQ/3ECh1AXCgb/4yFf7ssyB2HUD7+USCHjO/TSIjhGgP3TZ2ym088TDerrupCYb6qwXaoNg8KdlGI9oX5zTkWL8gALrjuh/onGfmZtOyhiqm7xJxpTMixernj949N/TRu+v7pwuiAtAdSYeXINBDIIEAuGyMReqNZJBQFZiMUOLjWbjXgEA0ePxu6In8FiBLWbguC+A1hgSB/BBIVP2n7wUGEP5s5wouAD7zwi8m7Dni0CeIOdS1Y+PZEyZ8+29PvfCrQ0eOOGilMH96YIpiiWX+kUIdM488cspa3fbOO28ebRidd1pm+JPbtuy4es3aj1bcfvvtoYHsBALf32vPPfdtqKqsuJiVaqmq2rWopqap+6WXguVGuTHFVza0WZgPSuYLW9aqv731dM30Uxs716xrv7y8fMT1ltn94gv/7DjCe+IeAAAgAElEQVTJFijzc1b0jYIKwDwDz+pwpS4AxvvmL1vCX6aJikwdZj7Q3hk4U3voDwKaQKJznkUeN0mmktClTlLMvIOFF4yorGy5vfGs+kKu6YEMggAIZEQg4Q15vGnAA42EqsD08pCFew0IROkhd1tr5LcAGcvCdVkArzEkCOSeQLzqvxSFv6IRAJ94YmHVqH2OeMkwfLJl0wvHHX98w9ZXXmk7y1e5x619uwMPiFJ2WOGuRTu2vH/j8cdfurV3V+DTSMyfd3Z1vbdjU+clV80NrEtkQk/9PeG4Qybuvc/IXyjD92x5edmVU6fOjKzL/u9Xlx9VWVb1S1K+L0ZKcZI9RJ7f1bmx9tPjL1r3/Jq7Thg2ZL9HQqHtd48fN2VGsq45Og4BMEdg82K2lAXA2G/+ikX4y0viMUjJEqhpaOvbvUqf82SFl5os+4ulZivm82LEvzeIVEtbYMovep8v+Dd6JZs4BA4CmRPImgBou4KqwORJydK9BgSi5Kjd3AL5zXP2snRd5tRr54wfPdNHsbrYJGshiV6epWfJn742MetzO5ft2X0m0apWIq7td75/+SD9nNOmiCxk4pt6275ERBPsmUN6vXHbRiI/cgoIxnNGwFn9l6bwl0gAzPsagNqRdet/G9Q/xx1xjj7f5ZVXV/iN8iF+YjU8FXiK6L2OXZsuWhFc92e9aceDD/5yyKZN22aQmFdv3bb9V5s3v/ujxsalnfFsNTbOHLn/fns9VFFZsbdS6qrKykMe1tV6b7/9RNX2jvfm+8qGXkbMZan4wSJvh7p3zjj6yMn3P/hg45DxEz737227Pmj47DEXLU+lfw7aQADMAdS8mSxlAdD+5g/CX95ONwxUYAL2Oc/Eq5nM6Xo9r2p/8Jssoiv7onb5YuKnhKQl2Fy7wuE2BMAC5xDDg0AGBBJev3qHRUXq8cHaTrAI+GDNeapflu41IBB56qzYLRjkN8/5zdJ1mTOvk68Vnr4AOPDSQP1reyccW+gSUnStFiCdomK03d3XCM8ZJBjOCQFbGxik8JdIACzImuFr//PgDIskdPTh37ztkUdaho45/MhfsK/igpSq7uxIwl3/sMJyxlFHnb1dP7VkyaIxzF23MdFpz7+w9vRFi5b+X7xE3Ngyp3n0PqNmCKnFVVWHXGdv/PHCC7/+ypARBz4szIk2IYljTnaSFQ6MO+wbkR1/X1m38r73331hzqmnNr2Tk5MgudGo+8nkJYzJDaJFHgmUqgCov/kj5ZvWOr9a33ThAQIlQUBP87OFPx3wlIbW7yiieiIe5wSgWD2klGq572eT/xoDBgJgSZwpCNKjBBJev6nuhGlz6ZsCTER4H018tmTxXgMCkUcvyt6wkN885jeL12VOvO5fO5z2YKa/20sBOdfhHkwFoC3sOdcNtysFnc9FC4DRgl6/Dw7BsGXV55j5Eb12eWy1YU4AwWhOCejPCiaZTQk290h17KL4vPDMml+fYHTt6vrsZ6944cUX7x5fMXTkbaTKTkk1CN2OhULdnZsajhl//kK73113tpwtbC4Khbq7Xn/jjS8FAks+dNpsaPjOKeOPGvt7IXnGMCr+58ILZ72mjz/88M0VR4w79DHLV/YpJh6SqhDJRGJZ4Xs3fPzi5acf37D1Xy/f9dUHgm88pqsS04kli21RAZhFmHk3VaoCYN5BY0AQKCICx11ySdmhI78yW5Gu/OO9ol1TdxrMLcsCPYveQgAsosTBFRDIjMCAN+TJ1gEUou2K5LdMch12A84sEYPoDYFoENBc1AX5dVGycu1qPFFOj+kUBtMVAENl1p+MED0sQicT9Yt30dV70VWF8TYY7Jta7JhyjOm/uT4jXGm/KATAYHBe+ejRbJ16amP41dce+LoodatSZYclItpbySYi5hYR2WCw8X7YCr3RsXPjY5/55Hfa7X7BYLC8o+PNJiJr1o7tu5Y8+dQbV91zzz079fHm5isOHjVq9MqysrJDmH3fv+ii2X3TdB9/vLFyn4M/dTKFw18oLxt6LCu1b9gyD1LKOICJfX1rNMVzUKy/hM2OHx499ryXgsGgUaDNP2zPIAC68rLsdRoCoJuzB99BIH0C35yz7BOVzPXE7NzNl5jYJKaWCvItuDtw3qYEloviDT39qNEDBEAg0S7ANpm6ue2NlmXpazzhQ0T+bDL5VzbXPQOieSUAgSivuPM+GPKbd+TFO2AiQW3mwgcPsMR4YjBrAAqHnuzvmyj2HmFwIEHP6YOu9osWFqPXEixewvAsDwSK6vOCFswmfKb8Up+vvIXY0JV3fY9e0a/LskJvKFIvihV+q9vsXmdZ3S/tCu98veOjdzdpATGW2a/uvfnAcrPjXrHkU5s+3DzjqjnX33PhhV8bcuKJJ/5k2NCqy1iV/XzLlnL/FVdc0RXbV0T476/eOWwEVx3gI+MoX9mwCWJZhwjTkayMoxUbIyV2cxCx3gyHdv3w6HGTV+Uhf8mGgACYjFAxH4cAWMzZgW8gkF0C1XODn1Zi1Yvw+dFvfvy+Fv/aAjV95e0JRi6qN/Ts0oE1EPA8gQGv31TXAWRWK4kMf1vgvIS733meZP4DhECUf+b5HBH5zSftIh+rmAVAjc45DZiEFunpv/p5ETljcf2kp4ocL9zLD4Gi+rzw73/ftlf5sIMaFfuuYFa66IEssbaaZtc/SORpkvBai+j1cuZ316595OOzzrq9Q5/STlS6mnD//SuHfvGL/s328/fee+OJZji8KhQKrfvwo49/UFlZcfgew4fdqHzGRpHh35w+/bL3ddvHH3/cN3zkuuM+2vrKhjO/dNN7sSl4/PFG3377HbqH5dtjXx+rQ5horCXmp4X5C2W+IUfoqcKWmF1khurffftfv4gnSOYnrX2jQADMM/CsDgcBMKs4YQwEipbAuXPuO73MMOpJ6HSnk4rVv1lP+Z0/5d4UnC+qN/QU/EUTEACBfgIDXr+J1gFk4sVCMsMJkpmWKDb9y+afvxGA80IAAlFeMBdsEOS3YOiLb+B8TgGOF32yKb32VOTevk8I0dedaxUWH1F4VAACRfV5Yc1rvxtbxurnlmUeJER/EKvrrxW+IWvCYdq8fft/d73++qNdNTXtppNTY2OjOuOMioOHjxz71TJV/mU2fMeSZb0S6tp42THHfOdj3Va3OfTw4VdKuHt+R0fnY4ZSw8orKj5p+KomXnjhjCdse6++2v51Lhsyn9jYk6zwa2Gz+6kdO/77x80fvvnPM85YEJk6bD90deCaNe1lnZ2bq/bZ59Chm3ZuGlPhKz9Bse9M0ww9R+EtLfb4BcirPSQEwALCz3hoCIAZI4QBECh6ArUNrd8SYr3T76eiP8Tznw1WLffNnxL59jaFR1G9oafgL5qAAAj0E0h6/cauAygkS3eaHf6hRlWAiadFwRS56YOqDv/qxumdgJxzAhCIco64oAMgvwXFX1yDO6fZ2sKa9rB/DT/9V8902741+SIh9DwXPVWYyN6YI94mIM51BWPbkWOdPyeh+LsJY/pvcZ1FBfcm6f1GPj188MFLhlTstf+eb6x578NLL7095BxbC2768nrttd8bb279d+We5SNPGl65zzcNo+xLpIzDibmirxRQrK1idv9k3OHf1JWvkQ047r335hFWuLNNyDpD18EyGfP33qfypxMn9kz9ffKFXx2417D9b1ZG2TnOab2KWMQKf2Sa3f/qCm3//c4t76zaf/8T39m0aZ153HGXmLZ9h6/87LO/9D300HtmATf/sN3BLsD5PIGzPRYEwGwThT0QKC4CNQ3LZhKp2UT0CadnitUyEm5pbZ7yXBoeF9Ubehp+oykIgABR0us3dh1Ai6xT9U6A1XOCR7KSABGdG/U6olQTdgHOy6kFgSgvmAs2CPJbMPTFOXD0TrzxfOzdsMOxA2+iSGxhL1YYdLaP3m34oeuIVFMiAVD3c/oXb7OQ4qQKr/JIIOn9Rh59iTuUFgXHjj3tQCmvHCuW+QUf+U5mw/dJVr49dYdEG3KIFX4uHNo14+hxU/6uRTotIN5zT8uXLMu6k4g2iKhLpk+fs17b0GMcMX7SZcpXcR0RD0sUc+86hGExu/8jZvjJnd1bH+kKdfyjc8vGd4pgum88t1EBWOgTOJPxIQBmQg99QaB4CUxq+M1eQ0nVEys97dcXdaNHvNhnGQt+c8Pkd9KMoOjf0NOMB81BoJQIJL1+ndOAmXh1W3PNqTag6jnBE1hRgEhO64fGXUTiDzbXLiolkAWIFQJRAaDncUjkN4+w3TJUlAjItMFis1qJ0e7cBCQixsWIgFrMsyy5g5m1INFXAWjH3b+Gn/1M/67AEXsLUhAAHWNi+q9bzqi8+pn0fiOv3sQZ7IknfnrAsD3HnFNZsddxTLQfK2NvS8x99U8ijmwUEk8EZBLTNEN3hzs+mjthwvTIGn933HH98HIf14Yt+WjMmBMeOvXUU8Miol577f4vsq/qNovV0bEu9Ih+YolY28iyPlSGb6NY5ibLsj6wzO43O7s+fv6dt55ZfdZZt+8qNKs440MALMKkpOwSBMCUUaEhCLiGQPW1wSOVSfUicrHTaWbeSkItR1VQS1NTTfcgAir6N/RBxIQuIFAqBFK6fmv9wTdEZIwint7aXLPUCUevJepTRoCJjut/nj/oFQEjHzbxyAkBCEQ5wVo0RpHfoklF8ToSbxfgQnkbLTpi+m+h8lDE48beb+jXuKZi81dX7/3x3wuGjDL2HVVZVr6vT9T+4qvcn4kOYlYHiJiHsDIOYTYOUGxUCOn/tG5nbukO7bq6c9umJccff2lkSvEvf/nLiGh46aWXRgS7NWt+PdJXud+vlFGmZ05ovU9EZJtlhd5mVm+JWBtIzHeF+B2fWO+FFb+3fdO6Dz/66O3NEyfestvOwUXGDgJgkSUkLXcgAKaFC41BoOgJ1PmXfdEUNZuJvul0lonXM6uW1sCUX2UQREoCQgb20RUEQCB3BFK6fu11AIPNtb2zUqIdqp6zbAorpacDj7WP6NcX6akEXJE790vaMgQib6cf+fV2frMSXVEJgAtWtRKxfpPYit1/s5JerxlJ6X6jGIPWouBDD11aNX78mcOIjBEhsvYwQ917ixU61Fc5YhyLHEUiRzGrjh1b355y3HGXvRIvjhdfue/y8rKhF1oib4qYaxWrdULyNhvGZunatc2ydm4TGbFjwoQaLSAmmnFcjIi0T1gDsFgzk4pfEABToYQ2IOAOAlPmtJ6nVGSzjxOjxD+mvysyFiwLTPlthpG49g09w7jRHQS8QCCl63dKw7JTmPii9ua66YmCrvMHLxaigIiM7hMBmZ8ViYiAj3oBVpHFAIGoyBKSZXeQ3ywD9aK5YhAAk00f9iJ3xDQoAindbwzKcgE6aVFwNa02Kv7xXNnIkYf7RMxypazRUjG866gxZ7wRz6VX3nl0VOjjjZZSZaGKimGh555bEo7dabgAoWRrSFQAZotkIexAACwEdYwJAtknUNPQ9j1m1tN+D4sW//i3bJktrddP7duOPoPRPfWGngEHdAUBNxJI6frV6wCGicbozT8GCrLaH5zFJAESKrfbicifFZO/rbnuGTcCKmKfIRAVcXKy4BrymwWIXjdRbAIg1v7z+hmXUXwp3W9kNAI6F5IABMBC0s90bAiAmRJEfxAoLIFTpjVW7rPf+Hohqmei4VHiH/HtFlFLe3PNa1nyEm/oWQIJMyBQAAJZv35r/cEmEbku+ksHtZLI8LcFzltXgBi9OiQEIq9mticu5Nfb+UV0IFBqBFyxBmCpJSWL8UIAzCLMvJuCAJh35BgQBLJGoPrq4MHEVj0T/zDaKHcx0QJLqKX9+pqtWRswZs2H3gV99ZsAHiAAAsVPIOsCYPXMYJWqoICQzIgWAWmJYtO/bP75G4sfiys8hEDkijQN2knkd9Do0BEEQKAICWT9fqMIYyxllyAAujn7EADdnD34XsoE6q5ZfrxphmczcW2M+PeOYmlpDdTenAM+eEPPAVSYBIE8EcjJ9Tuxfsl+Q42qABNPi4pD5KYPqjr8qxund+YpPi8PA4HIy9lFBaC3s4voQKD0COTkfqP0MBZtxBAAizY1KTgGATAFSGgCAkVGYMrVrV+PbPYhdKrTNWb+FzG3tM2vbs2Ry3hDzxFYmAWBPBDI2fVbPSd4JCvROwOf64xDKdXUOr8aVcKZJxcCYOYMi9kC8lvM2YFvIAAC6RLI2f1Guo6gfU4IQADMCdY8GYUAmCfQGAYEskSgxt92EQvXC8kxMeLfI8zc0jq/+s9ZGiqeGbyh5xAuTINAjgnk9PqtnhM8gRUFiOS0/ji4iyiyM/CiHMfmdfMQiLydYeTX2/lFdCBQagRi7zduIKKrSw2Ch+O9nojm2PGxhwP1ZGgQAD2ZVgTlUQI1/rbZJFxPJPtEiX8k91ii9Hp/L+Y49JwKCDn2HeZBoNQJ5Pz6PXfOfaf7lBFgouMcIuAHvSLgnaWegAzih0CUATwXdEV+XZAkuAgCIJAyAb08kXM20pNE9PmUe6NhsRP4BxGdCAGw2NOUwD8IgC5NHNwuKQLV/uBokshmH/WxgTPRjVUVwxYsbZr0fh6g5FxAyEMMGAIESpVAXq7f6jnLprBSejrwWBu0kKxnYl0JuKJU4WcYNwSiDAEWeXfkt8gTBPdAAATSInAEEa2L6aHvC+amZQWNi5HAfCLyOx1DBWAxpmkAnyAAuixhcLfkCEy++r5jfKxmS8wC+4rVJr3L79GVU1oaG9nKE5i8CAh5igXDgECpEcjb9VvnD14sRAERGW1DZuZnRSLTgR8tNfBZiBcCURYgFrEJ5LeIkwPXQAAEBkVAV/1Pj+l5ExHNHJQ1dCoGAno5lytjHLkTAmAxpCYNHyAApgELTUEgzwSmNCw7RZHSVX8TY75peYVYtbQFqpfk2aW8CQh5jgvDgUApEMjr9VvtD85ikgAJldtwReTPisnf1lz3TCkAz2KMEIiyCLMITSG/RZgUuAQCIJARgf2I6CUiGhVjRS9XpCvIVmVkHZ3zSWASkV7jmY6NGXQTEU2AAJjPVGRhLAiAWYAIEyCQAwI1c9tqIpt9iBwfY/4vzGpBW6D6oRwMm8xkXgWEZM7gOAiAQFoE8n791vqDTSJyndNLZrWSyPC3Bc6LnR6UVjAl1hgCkbcTjvx6O7+IDgRKlcDJRPQAEY2MA+ApIvo5Ed1TqnBcEPeFRHQZEX0ujq8fE9E3iejvEABdkEmnixAAXZYwuFsSBGobWn9IetqvyCFRATMvF5Na2m+oebpAIPIuIBQoTgwLAl4kkPfrt3pmsEpVUEBIZkQBFVpiGKZ/2fzzN3oRdA5igkCUA6hFZBL5LaJkwBUQAIGsEjiBiPSMpaMTWF3fKwTeRkShrI4MY4MhUEZEP+gV/vRajvEeL/dO7458HoUAOBjMBewDAbCA8DE0CMQQqJ4XHKa6SVf96Wm/VTGHb6vw8YJ7flrzRgHB5V1AKGCsGBoEvEagINfvxPol+w01qgIcs44pidz0QVWHf3Xj9E6vgc5BPBCIcgC1iEwiv0WUDLgCAiCQdQKKiPT6f5cPYHknET3s+PdB1r2AwUQE9uldbkovOaX/DR0A1S296wD2rT8PAdBlJxYEQJclDO56lsDkht8cZpBPC3/fcwbJzLuYuaWsu6PlngXf1m+OhXwUREAoZMAYGwQ8RKBg12/1nHuOZFWu148518lTKdXUOr9aix94DEwAApG3zxDk19v5RXQgAAI9BL7YW11WlwKQvzjEQL2WIB7ZJTDBIfp9OQXTrUSkqzT/L7YtBMAU6BVTEwiAxZQN+FKqBCb7l3/OEFOLf5OdDJj5TRJuaWuu1i+4xfAomIBQDMHDBxBwOYGCXr/Vc4InsNKLSMtp/Ry5iyiyM7DeWQ6PxAQgEHn77EB+vZ1fRAcCIBBNQE8H1mvL6ammqTzWEtGzRPTP3p/6d8weSIVcT5tKItJryut/x/X+PCrF7vozqF6rUU/7jfuAAJgiyWJpBgGwWDIBP0qVQM3VbWeximz2ob8V638wP81iLWhrrmsvIjYFFRCKiANcAQE3Eij49XvunPtO9ykjwD03oL0P/qBXBLzTjVDz5DMEojyBLtAwyG+BwGNYEACBghLQOwVrEfAiIjo4TU+ejxEFnyMiM00bXmxuENFnYsS+T6cZ6AYiuqu34u/9ZH0hACYjVGTHIQAWWULgTkkRqPMHLzbFms3EMd/C8CqDqWVZoEaXvxfTo+ACQjHBgC8g4DICRXH9Vs9ZNoWV0tOBx9r8hGQ9E+tKwBUuY5ovdyEQ5Yt0YcZBfgvDHaOCAAgUDwG906y9Bp2uVBvM43Uisv/9x/G7fm7LYAwWaZ89ieiw3n+HO363nxuM27qq0l6DUe/QnPIDAmDKqIqjIQTA4sgDvCgxAtVBo/owqmcl9SQ0Mip6oSUs0tJ2Q90rRUilKASEIuQCl0DADQSK5vrVX34IUUBERtvgmPlZkch04EfdADPPPkIgyjPwPA+H/OYZOIYDARAoagKHEtHXHYJgNjSmD3sFwTeJ6KPef5scvzuf21UAOnrzx71j/o2K+XtMr9jXd++UgZ/SK/j9vvfnoDeZzEZyMogDXdMlAAEwXWJoDwKZEbhg7or9u62wXu9vZrQlFmZpURVDWpY1nqXfhIrxEU9AKEY/4RMIgMDuBPTNnnPDjaaYv/PKrNofnMUkARIqtwcWkT8rJn9bc90zeXWm+AeDQFT8OcrEQ+Q3E3roCwIg4GUCWhj7f4616/QSIkfmOGC96aItDnYRUTcRJfrpPKZ/1/c0+l9Fkp92Gy36aaFvoJ13sxHuq3HWUezIhmEIgNmgmEcbEADzCBtDlTyB2qtbPyXMs4noAicMZt4oIi3B5tobixxSrABY5O7CPRAAgQEIFFQA1H7V+oNNInJd9OuhWklk+NsC561D9voIOAUiLeSWwqPUPlPo99eCX5OlcGIhRhAAAdcT0LOn7M0s7J+HuD6q7AXwlkPsszdO+Th75qMtldqbda445s0uBMC8ocZAJU6gpqHtq8yRzT6+FvOy+SIrXtA2v/puFyCCAOiCJMFFEEiRQMHFhuqZwSpVQQEhmRHls9ASwzD9y+afvzHFWLzezBYAvR5nqcdX8Guy1BOA+EEABFxLQFcKxlsXz14jr2+2gWsj7HdcVxrqdQ3tdQ5j1zvMSmVfqpwgAKZKqkjaQQAskkTADU8TqJsbPN+0aDaT6F2ZnI/HhLilvbnmDy4BAAHQJYmCmyCQAoGiEBsm1i/Zb6hRFWDiadEioNz0wca1/tVLGztTiMXrTbQAaFf+2ffa+m/9eyGed/J2+pPN50v1M4Vzmr7Xz2vEBwIgAAL5IqB3GdZi4P5J1tnTU3ILIRZqUc9ehzDeGoV6SvJ/e0U/vUtv0TxK9c26aBKQriMQANMlhvYgkB6B6qtbZ+jKPyI6IOqTEVMrsa+lbf7kf6VnsaCttQCYzUei94xsT3HL1zjZZANbIJBrAvq6KAqxoXrOPUeyKtc7A5/rDFop1dQ6v7oofMx1MmAfBEAABEAABECgKAgM7xUJ9VRj53p+cdf2O/TYU78xbOS+XxPLIlaKdny88Y9vvPj4QwOsG+hcT1DvTqwFv21FEfkgnIAAOAhohewCAbCQ9DG2lwmcc+WSPcurhtWzWPVCVBYj/t3CqqKl9WfnvO1lBogNBEAABFIlUD0neAIrChDJaf19uIsosjPwolTtoB0IgAAIgAAIgAAI5ItA3dz2Rsuy+ookSu3LSwiA+TrTsjQOBMAsgYQZEHAQqPW3jhMyZpNY340R/raJRS3bd21s+f0tV+hvf/AAARAAARDoJXDunPtO9ykjwD2Le/c++INeEfBOgAIBEAABEAABEACBYiIAAbCYsgFfkhKAAJgUERqAQFoEavxtJ7NwvZCcHdPxtd71/m5PyyAagwAIgEAJEaies2wKK6WnA4+1wxaR9cysKwFXlBAKhAoCIAACIAACIFDkBCAAFnmC4F40AQiAOCNAIHsEqhuC5xos9ZbQ551WFdM/TIls9nF/9kaDJRAAARDwJoE6f/BiIQqIyGg7QmZ+ViQyHfhRb0aNqEAABEAABEAABNxGAAKg2zJW4v5CACzxEwDhZ41AdUPwEibRm330Va1o40z8O2FpCQZq/561wWAIBEAABDxOoNofnMUkAZL+3fhE5M+Kyd/WXPeMx8NHeCAAAiAAAiAAAi4gAAHQBUmCi/0EIADibACBzAh8/fKbK4YP2beeFdWL0Igoa6x+xWQuaAvUrctsFPQGARAAgdIjUOsPNonIdc7ILZGVhir3twXOw+tq6Z0SiBgEQAAEQAAEiooABMCiSgecSUYAAmAyQjgOAokJ1F3z24PE6tLC3+XOVkwUElYt3R07Wn5703S9vTseIAACIAACaRKonhmsUhUUEJIZUV2FlhhGpX/Z/LM3pmkSzUEABEAABEAABEAgawQgAGYNJQzlgwAEwHxQxhheJFA7d8VnScJa/KuLie9dEWlpv75usRfjRkwgAAIgkE8C0+at2m9n1/YAE0+LFgHlpg82rvWvXtrYmU9/MBYIgAAIgAAIgAAI2AQgAOJccBUBCICuShecLRIC1Q3BM3vX+zvN6ZIQP2coWtA6v+a+InEVboAACICA6wlUz7nnSFblemfgc53BWGQ1LW+e2uj6ABEACIAACIAACICAKwlAAHRl2krXaQiApZt7RD44ArVz278tlswmkmOdFpj5j7ryDztUDo4reoEACIDAQASq5wRPYEUBIun74oWZu0WkIdhcuwj0QAAEQAAEQAAEQCDfBCAA5ps4xsuIAATAjPChc4kRqGlou4qZ60Vk35jQ72WRBW3X171QYkgQLgiAAAjkjcC5c+473aeMABMd1z8of0Ak/mBz7Z15cwQDgQAIgAAIgAAIgAARQQDEaeAqAhAAXZUuOFsgAlMbH9zb6tpVL8L1RMIxbsdoygAAACAASURBVCwqV76We+dPfq9A7mFYEAABECgZAtVzlk1hpfR04LGOoF8jMhqCzVNWlAwIBAoCIAACIAACIFBwAhAAC54COJAOAQiA6dBC21IkUDundbww1xPT9Kj4mT4Wi1vaX6cWaq8xS5ENYgYBEACBQhCo8wcvFqKAiIy2x2fmZ0UilYCPFsInjAkCIAACIAACIFB6BCAAll7OXR0xBEBXpw/O55jAVH/wy6aQrvqb5BxKSNYarBa0BmruyLELMA8CIAACIBCHQLW/dRYTB0io3HH4MSZpaGuuewbQQAAEQAAEQAAEQCDXBCAA5pow7GeVAATArOKEMQ8RqG1orRZWs0nkBGdYzPx/YklL8PraBz0ULkIBARAAAdcRqPUHm0TkOqfjlsjKyrKquff+9OxXXRcQHAYBEAABEAABEHAVAQiArkoXnIUAiHMABHYnUNvQ/gNi0Zt9jIk5usJko2VFYMpT4AYCIAACIFBYAtUzg1WqggJCMiPqixripVUVQ/1Lmya9X1gPMToIgAAIgAAIgICXCUAA9HJ2PRgbBEAPJhUhDZrAhbPvHhoqr9LCn/43JMbQ/5oUblnR/K3XBz0AOoIACIAACGSVwLR5q/bb2bU9wMTTYkTAxVbXO/72RbM6sjogjIEACIAACIAACIBALwEIgDgVXEUAAqCr0gVnc0jgwmuDh3aFZTYR/SBmmA5mbrHKqaW9qWZHDl2AaRAAARAAgUEQqJ5zz5GsyvXOwOc6u1tkNS1vnto4CJPoAgIgAAIgAAIgAAJJCUAATIoIDYqJAATAYsoGfCkUgeo5wRPYoHoSmeL0gZnfIrEWtDXX3Voo3zAuCIAACIBAcgLnXxM8IWxSgEhOs1szczcR+dsCNQuTW0ALEAABEAABEAABEEiPAATA9HihdYEJQAAscAIwfMEJ1PrbvyFi6cq/L8eIf88KS0twfm2w4E7CARAAARAAgaQEps5deXrYCgWY6DiHCPghE/mxa3tSfGgAAiAAAiAAAiCQJgEIgGkCQ/PCEoAAWFj+GL2wBGr97dNJrHohGh/jycMWWS3Lm6euLqyHGB0EQAAEQCAdAtVzlk1hpfR04LGOfq8Js789ULM8HVtoCwIgAAIgAAIgAAIDEYAAiPPDVQQgALoqXXA2SwQaG0W93Lm8XjHVW2KNcpplkqVhsRasuP78NVkaDmZAAARAAATySKDOH7xYiAIiMtoelln9U7H4l82v+VMeXcFQIAACIAACIAACHiYAAdDDyfViaBAAvZhVxDQQAb1jZEfXjtlCdFVsOyFpIVYt7YGaD0ERBEAABEDAvQSq/a2zmDhAQuWOKB7zGey/72c1T7s3MngOAiAAAiAAAiBQLAQgABZLJuBHSgQgAKaECY08QqD66uCxivWUX74wOiT+gPR6f4HaBR4JFWGAAAiAQMkTqPUHm0TkuhgQ95f7Kv33/vTsV0seEACAAAiAAAiAAAhkRAACYEb40DnfBCAA5ps4xisUgbq57V8RkXoROcPpAxOviWz2Eai9q1C+YVwQAAEQAIHsE6ieGaxSFRQQkhkxr/tLqyqG+pc2TXo/+6PCIgiAAAiAAAiAQKkQgABYKpn2SJwQAD2SSIQxIIHaue111CP+fTaqIdPjliUty6+v+z0QggAIgAAIeI+AXvZhZ9f2ABNPixEBF1td7/jbF83q8F7UiAgEQAAEQAAEQCAfBCAA5oMyxsgaAQiAWUMJQ0VKoM7fdoUlXE8kBzpdFJI2w/AtaP3ZlGeL1HW4BQIgAAIgkAUC1XPuOZJVud4Z+Nyo9wGWH7cH6uZlYQiYAAEQAAEQAAEQKEECEABLMOluDhkCoJuzB98HIlB9dXAPvcuvEM0mkooY8e9WEtXSfn3NBlAEARAAARDwPoHzrwmeEDYpQCSn2dEyczcR+dsCNQu9TwARggAIgAAIgAAIZJsABMBsE4W9nBKAAJhTvDBeIALVDcGxirT4J5dEC3+0nYlaPnj/lZbVSxs7C+QehgUBEAABECgAgalzV54etkIBJjrOIQJ+yET+1kDNHQVwCUOCAAiAAAiAAAi4mAAEQBcnrxRdhwBYiln3dsx1Vy87SZSh1/s7xxkpM78uIi3B5tr/9TYBRAcCIAACIJCIQPWcZVNYKT0deKyjzWvC7G8P1CwHORAAARAAARAAARBIlQAEwFRJoV1REIAAWBRpgBNZIjDVv/wci8zZInRyjMknI5t93FC3MktDwQwIgAAIgIBLCdT5gxcLUUBERtshMKt/Khb/svk1f3JpWHAbBEAABEAABEAgzwQgAOYZOIbLjAAEwMz4oXfxEKjzL/+uiKWn/R7h9EqIHjDYWtAamPp/xeMtPAEBEAABECgkgVp/cJaQBEio3OHHYz6D/ff9rObpQvqGsUEABEAABEAABNxBAAKgO/IEL3sJQADEqeB2AvPmBcvXdlE96Q0/RPZwxsPMd1gGtbT/tOZVt8cJ/0EABEAABLJLoNYfbBKR62Ks3i8+9uN9I7usYQ0EQAAEQAAEvEgAAqAXs+rhmCAAeji5JRDat+asODCszNlCMiMqXKYwidWyk6yWVc3f2lwCKBAiCIAACIBAmgSqZwarVAUFYt9DmHhpVcVQ/9KmSe+naRLNQQAEQAAEQAAESogABMASSrYXQoUA6IUslmYMdQ3LP0Ms9ZZYU2MI/JfIWhBsnrqoNMkgahAAARAAgVQJTJu3ar+dXdsDTDzN2YeJF1td5G9fVNORqi20AwEQAAEQAAEQKC0CEABLK9+ujxYCoOtTWJIBnD93+RmmXu9P5CsxAF5gkpa25rrflCQYBA0CIAACIJA2geprg0dyWPTOwOdGiYAsP24L1M1L2yA6gAAIgAAIgAAIlAQBCIAlkWbvBAkB0Du5LJVIps5dfoFIpPLvk1ExM/0pZJot999wPnZwLJWTAXGCAAiAQJYInH9N8ISwGREBT7NNMnM3EfnbAjULszQMzIAACIAACBSYQF3DsjGtzVPfLLAbGN4jBGIFQCFZ2t5cN90j4SUNg5O2QIOiIgABsKjSAWeSENC7NpKQ3ul3P2dTZrnPYtXSPr/meUAEARAAARAAgcEQmDp35elhKxRgouMcIuCHTORvDdTcMRib6AMCIAACIFAcBLRQIyIXtQVqDi0Oj+CFFwiUup4CAdBlZ3Gpn7AuS1fJuvtt/8pRXRSe3Sv+GVEgRG7qFGl54Iap/y1ZQAgcBEAABEAgKwSq5yybwkrpSsCxDoOvCbO/PVCzPCuDwAgIgAAIgEDeCNjCn4iMUcTTW5trluZtcAzkeQKlrqdAAHTZKV7qJ6zL0lWS7k71Lz/KFKknsv4nGoBstohb3vj4zwv+efvtoZKEg6BBAARAAASyTqDOH7xYiAIiMto2zqz+qVj8y+bXYJmJrBOHQRAAgXwTuPzmh0cYIXpYxPrj4tnf+HGuxs/XOPH8dwp/9vFgcy30ilwlu0TtlrqeggvKZSd+qZ+wLktXybl7/jUrvmRZll7v7xsx4t86i6hleXPdr0sOCgIGARAAARDIOQG95ISQBEio3DHYYz6D/ff9rObpnDuAAUAABEAgRwRmLnzwAEuMJ0joYCJrXq4EwHyNE4spnvCn26D6L0cnVImbLXU9BQKgyy6AUj9hXZauknK3pqFtMhPr9f4+FxP434S5pT1Q80BJAUGwIAACIAACeSVQ6w82ich1MYPeLz72t/+05tW8OoPBQAAEQCBLBPIlzOVrHBtLIuHPPo7qvyydQDATRaDU9RQIgC67IEr9hHVZukrG3Vr/8u8TWfUiErVIryWykpW1oD1w/j9KBgYCBQEQAAEQKAiB6pnBKlVBASGZ4XSAiZdWVQz1L22a9H5BHMOgIAACniAwY8FD1xGppr5gmDYoNk9aNOusd50BzmhZ9TlmfkSI9rCfN1hNWXjVmSvsv51t9DFTzGoirtXHmWiriJyxuH7SU7Nu/MNkU6zd1jN12puxYFWr3bfHfnSVoH3caTfaR2kz2GhPNk62kphM+NPjoPovW7RhJ5ZAqespEABddk2U+gnrsnR53t1LGh8csq2zs15YZovIsKiAmX7ZHe5o+W3LtP94HgQCBAEQAAEQKAoC0+at2q+ja6cWAafFiICLrS7yty+q6SgKR+EECICAqwjsLrL1uO8U1fTfu4mEUVFK2+LZk+oi7eKIhNGvWT0ioKGMAxMJc6Ey60896wLSybvDTDSWtFnlfElfv14Rk6XsxFwLgKkIf3YcqP5z1eXhKmdLXU+BAOiq05Wo1E9Yl6XL0+6ef82qQyxrl17v77LoQKVTb/ZRURFa8JumC7Z5GgKCAwEQAAEQKDoC1dcGj+Sw6J2Bz3U6p1j9xRLrcWYW/VC6ToaViJjCwkJkEbEvcizywZ5ZiK2eY4oo8rz+r/eY/tuyTDGMMor8VD6xyCTLEjFYReyx8olYYbGERCkVsaGPhSNjWGSwT8ISjtj0sRJLRDjS16T+37UvPcf08z4uE8sKC0uZkNEzHivdh7S7Yintl4ih43MeYxFLlOjwDTIoXjttN2JHqYiNCsOgbm1TQuLj8sj4SpWLaYUi7ZRSYloiZcqQMIXJsiwpY/07kX5O/63b+nyVpH8qSwn5iHQfZVoSNnxSFrFjiWla4isr6ztmKkOIQsSWT0xl9Yyn+5iWKMMnRN3U/ztRpfLJrsgxS8qpnMJmhyhjaE+7sCnKKJOQackeFRW0I7xLusOm7FlZSaHIsXLRP4k6yfCNkO7QDqmiKuouM6UrZMoIX7nsIqIRZZXSFdrak6/ySunsCouvOyw0fDh1dn0svs4q0TVfZZ1DZFfnh7JjV7fstddepH/uXzVcaBTR9l1dUrmzU7YM20v2J6LNWzvkw80vy5gxX6aNm16UE0aeJi/Ty/T6e5vlrE+Mk8Y1H0qwuppefrlJGhsbI6dh5NzEI28EoqvweqrrYivotLAX77lYUdCu3Itq66gkjBYQe8ZKNDXXbhuvYnBgYVLa7IpBZyVhrqYApyP8aV5CslaRQsV23s7wEhuIaYzeYdqOWkiWtjfXTS8VChAAXZZpCIAuS5hH3a1tWPH/hEL1RFwdE+IGS8wFy68//xaPho6wQAAEQAAEXEDg/GuCJ4TNiAh4mu0uE5tCEV0MDxBwNQEm1mq0aFmaSZGw9IrYQsJaP4kI2lpMjojOuqFijvzeI4DrzkKqVwxnfSyiu0T69BwjLY5bETXc7tPTrFcM1+2ZSfehiD96aCZtMiJ462MRmxHFMvKLFtMj/0ds9PyvtP/aV1JiUa/QSyxWr8+9HXtj0qZ6/OoZXgvjlqiIaK6tRMa1xdEeQPq4nlDK8qfWQO2PBpP4vim0TH83y2jiLVdM3BZvt9w+8S5manB/W12p11OZFy0W9k/ZjSfCxXsunk0dW/Tz/Xajn++TPvoqEvUz2RYA0xX+BpMb9AGBTAlAAMyUIPrnlAAEwJzihfEUCFwwd8WkLis0m4lPcTYXon8SWS3tzVPbUjCDJiAAAiAAAiCQUwJT56483RIzIGIdl9OBYBwEQKDoCVhEP1neXBu7SVBKfscTAON1HKhd7DHVJePtdQKTVeElFwUThdE/DVi3SFR1aPfOpgBY17BsjJCxREiiPi+kBByNQCCPBCAA5hE2hkqfAATA9JmhR/YIVDcsm8as6kno6Gjxj39PFF7Q3nz+Y9kbDZZAAARAAARAIDMC1f7gFBZdCSgHCtGTsV9eZWYdvUEABNxCQCn1k9b51aUtAMZsYhK7MUk2BUD7vIAQ6JYrpHT9hABYurl3ReQQAF2RJs86WdvQ+gMhvoGIhvYHKXeHwt0t9y/49kueDRyBgQAIgAAIuJZAnT94cdgMD/f5yvbUQfTMgmQOWxb5InMpmS29Xh8bTBLmyM++dsSmJWSwivSxxHIc03Mc9eKAJjMrPbsxMkGSObIUX8SOZYVJ2X0tPYY+GpklGemr+0T6WqaezhgZQ8Tqmf+oj0XmWEYeehKlXpQw8rduS2RGbJhicsQ/MtiUMBl6XOk5psfSMy8j40Z+tXrisKxev3p9JSaLLGbSdiPRR8aOzOnsWXNOPx8xYvVMFo34bfX6TdrXPo6RiaWReZg9zLQtm4umInoutt48oXcMzaInEbqDHj2ydGEkeMWm6Kmq+nBk5mjEb52HCCvtSMTVSByRiK1e3yOu98YUmRjb609k34bIfNVevnqiaG98kVmskdz32IzMso0417MiZGS8nvmwPT73+qV9MqUnvz0+6PB6DWk7EVM9edA56Omr+n7Xq1HqyHrtRTpE2OvBI75YLKLbR84ALOE0iFcjZv5xW6Bm3iC6Ut8GIDFTe/XzzHygPS14sFOAB1MBmGgKcKL4osU9+1UlehfjXAiAtj/pCIHM/Lwp5szB5Ap9QCBdAj6iN1ubp76Zbj+3tscbiMsyBwHQZQnzkLs1DW3zlNKLsvCX7XJ+S6wFVWZFyz0LzvvAQ6EiFBAAARAAARAAARAoZgLc2NjIRx89j2va26nxmNH84H/X8WH778VH09H09MeP8b6jjuU33/wLjd7raN5rjyruGFrOtHEjdQ6t5OFDKpg2Eb3XsZ2HDSnnUNfOyGfCIZWjOVS5i2krUbiygysrRnJlVwfvIKLKCh+HuztZfwdcUebjcKiTy8t8/FHHLqooM7g8ZHAHdVB52TA2w9u4zDe0R8w1u7nMZ/CWzk4q9w3lYT7Fu8Kh3mMh9vm04F5OlrmTfUYVW0aYu7uJhhiKO61w77Fd7DMq2Wco7u7uJv3TMhRTKESGUcGiwqx/hkK7ev42tZAcIsvS7Uz2Rf4maruh7snBJDXeJiBOsYx71wZ0Tuu11/rT4zk39oi3CchgBECnXeeGH85pvk67ThHTIDXLEusOIb1lTf804VwKgOkKgRZZpy5vnrp6MPlCHxAAgcQEIAC67OyAAOiyhHnI3bq5bY2WRX3fnBrMj943v/pr2InOQ0lGKCAAAiAAAiAAAiAAArsR6BPQ4rCJFtoeuo5INcVH2L8pRyKhLvmGHz2W9ZjCoSctMZ4goYNjx7NFSb1hSdxdjB3TgW3/420UEjtNOFunRrKKQCZe3dZcc2q2xoMdEACBHgIQAF12JkAAdFnCPORurACoFDW1zq9t9FCICAUEQAAEQAAEQAAEQAAE4hJwVvL1fpDeKiJnLK6f9JSzQ/QOv/2C3cKrzlxht0tHANR9okU8/YxDTFywqpWIa/t9iF/V5xQFo4RGx9TmgcbJxWkxkBCIKsBcEIfNUicAAdBlZwAEQJclzEPuQgD0UDIRCgiAAAiAAAiAAAiAAAgUCYF4QiCqAIskOXDDUwQgALosnRAAXZYwD7kLAdBDyUQoIAACIAACIAACIAACIFBkBGKFQFQBFlmC4I7rCUAAdFkKIQC6LGEechcCoIeSiVBAAARAAARAAARAAARAoEgJ2EKgdg9rARZpkuCWKwlAAHRZ2iAAuixhHnIXAqCHkolQQAAEQAAEQAAEQAAEQKDICWghULvY2jz1zSJ3Fe6BgCsIQAB0RZr6nYQA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnIXQiAHkomQgEBEAABEAABEAABEAABEAABECgpAhAAXZZuCIAuS5iH3IUA6KFkIhQQAAEQAAEQAAEQAAEQAAEQAIGSIgAB0GXphgDosoR5yF0IgB5KJkIBARAAARAAARAAARAAARAAARAoKQIQAF2WbgiALkuYh9yFAOihZCIUEAABEAABEAABEAABEAABEACBkiIAAdBl6YYA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnIXQiAHkomQgEBEAABEAABEAABEAABEAABECgpAhAAXZZuCIAuS5iH3IUA6KFkIhQQAAEQAAEQAAEQAAEQAAEQAIGSIgAB0GXphgDosoR5yF0IgB5KJkIBARAAARAAARAAARAAARAAARAoKQIQAF2WbgiALkuYh9yFAOihZCIUEAABEAABEAABEAABEAABEACBkiIAAdBl6YYA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnIXQiAHkomQgEBEAABEAABEAABEAABEAABECgpAhAAXZZuCIAuS5iH3IUA6KFkIhQQAAEQAAEQAAEQAAEQAAEQAIGSIgAB0GXphgDosoR5yF0IgB5KJkIBARAAARAAARAAARAAARAAARAoKQIQAF2WbgiALkuYh9yFAOihZCIUEAABEAABEAABEAABEAABEACBkiIAAdBl6YYA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnIXQiAHkomQgEBEAABEAABEAABEAABEAABECgpAhAAXZZuCIAuS5iH3IUA6KFkIhQQAAEQAAEQAAEQAAEQAAEQAIGSIgAB0GXphgDosoR5yF0IgB5KJkIBARAAARAAARAAARAAARAAARAoKQIQAF2WbgiALkuYh9yFAOihZCIUEAABEAABEAABEAABEAABEACBkiIAAdBl6YYA6LKEechdCIAeSiZCAQEQAAEQAAEQAAEQAAEQAAEQKCkCEABdlm4IgC5LmIfchQDooWQiFBAAARAAARAAARAAARAAARAAgZIiAAHQZemGAOiyhHnI3VgBkIgag821TR4KEaGAAAiAAAiAAAiAAAiAAAiAAAiAgCcJQAB0WVohALosYR5yt6ahbZ4W/eyQlKKm1vm1fX97KFSEAgIgAAIgAAIgAAIgAAIgAAIgAAKeIgAB0GXphADosoR5yN1YARAVgB5KLkIBARAAARAAARAAARAAARAAARDwNAEIgC5LLwRAlyXMQ+6iAtBDyUQoIAACIAACIAACIAACIAACIAACJUUAAqDL0g0B0GUJ85C7qAD0UDIRCgiAAAiAAAiAAAiAAAiAAAiAQEkRgADosnRDAHRZwjzkLioAPZRMhAICIAACIAACIAACIAACIAACIFBSBCAAuizdEABdljAPuYsKQA8lE6GAAAiAAAiAAAiAAAiAAAiAAAiUFAEIgC5LNwRAlyXMQ+6iAtBDyUQoIAACIAACIAACIAAC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" - } - }, "cell_type": "markdown", "metadata": {}, "source": [ - "![chatgpt-plugin.drawio (2).png](attachment:ddd5ff28-8281-4908-9c02-81954bffe57c.png)" + "![kdbai-chatgpt-overview](kdbai-chatgpt-overview.png)" ] }, { @@ -105,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -121,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -139,137 +134,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of unique contexts: 2648\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
idtitlecontextquestionanswersmetadata
07ba1e8f4261d3170fcf42e84a81dd749116fae95BrainAnother approach to brain function is to exami...What sare the benifts of the blood brain barrir?{'text': ['isolated from the bloodstream'], 'a...{'split': 'train', 'model_in_the_loop': 'Combi...
12936a8460bfffe437b54cf3ec1e825a3b7b5627a1BrainMotor systems are areas of the brain that are ...What do you think with?{'text': ['brain'], 'answer_start': [467]}{'split': 'train', 'model_in_the_loop': 'Combi...
24e40737d487964dbcd26a223f2799cf56390a98a8BrainThe brain is an organ that serves as the cente...How are neurons connected?{'text': ['synapses'], 'answer_start': [602]}{'split': 'train', 'model_in_the_loop': 'Combi...
37a0f8e785a10f6e21e24207d24ba2823162383062BrainThe SCN projects to a set of areas in the hypo...The body's central biological clock is contain...{'text': ['SCN'], 'answer_start': [4]}{'split': 'train', 'model_in_the_loop': 'Combi...
536d753d4a8878b5f5bc496d9a369b8c0b212079a0BrainThe brain contains several motor areas that pr...What is at the highest level?{'text': ['the primary motor cortex'], 'answer...{'split': 'train', 'model_in_the_loop': 'Combi...
\n", - "
" - ], - "text/plain": [ - " id title \\\n", - "0 7ba1e8f4261d3170fcf42e84a81dd749116fae95 Brain \n", - "12 936a8460bfffe437b54cf3ec1e825a3b7b5627a1 Brain \n", - "24 e40737d487964dbcd26a223f2799cf56390a98a8 Brain \n", - "37 a0f8e785a10f6e21e24207d24ba2823162383062 Brain \n", - "53 6d753d4a8878b5f5bc496d9a369b8c0b212079a0 Brain \n", - "\n", - " context \\\n", - "0 Another approach to brain function is to exami... \n", - "12 Motor systems are areas of the brain that are ... \n", - "24 The brain is an organ that serves as the cente... \n", - "37 The SCN projects to a set of areas in the hypo... \n", - "53 The brain contains several motor areas that pr... \n", - "\n", - " question \\\n", - "0 What sare the benifts of the blood brain barrir? \n", - "12 What do you think with? \n", - "24 How are neurons connected? \n", - "37 The body's central biological clock is contain... \n", - "53 What is at the highest level? \n", - "\n", - " answers \\\n", - "0 {'text': ['isolated from the bloodstream'], 'a... \n", - "12 {'text': ['brain'], 'answer_start': [467]} \n", - "24 {'text': ['synapses'], 'answer_start': [602]} \n", - "37 {'text': ['SCN'], 'answer_start': [4]} \n", - "53 {'text': ['the primary motor cortex'], 'answer... \n", - "\n", - " metadata \n", - "0 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "12 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "24 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "37 {'split': 'train', 'model_in_the_loop': 'Combi... \n", - "53 {'split': 'train', 'model_in_the_loop': 'Combi... " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "data = load_dataset(\"adversarial_qa\", 'adversarialQA', split=\"train\").to_pandas()\n", "data = data.drop_duplicates(subset=[\"context\"])\n", @@ -286,29 +153,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'text': 'Another approach to brain function is to examine the consequences of '\n", - " 'damage to specific brain areas. Even though it is protected by the '\n", - " 'skull and meninges, surrounded by cerebrospinal fluid, and isolated '\n", - " 'from the bloodstream by the blood–brain barrier, the delicate nature '\n", - " 'of the brain makes it vulnerable to numerous diseases and several '\n", - " 'types of damage. In humans, the effects of strokes and other types '\n", - " 'of brain damage have been a key source of information about brain '\n", - " 'function. Because there is no ability to experimentally control the '\n", - " 'nature of the damage, however, this information is often difficult '\n", - " 'to interpret. In animal studies, most commonly involving rats, it is '\n", - " 'possible to use electrodes or locally injected chemicals to produce '\n", - " 'precise patterns of damage and then examine the consequences for '\n", - " 'behavior.'}\n" - ] - } - ], + "outputs": [], "source": [ "# extract text data from the dataset\n", "documents = [\n", @@ -328,7 +175,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -345,35 +192,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4aff214f16364f57b70ff92e4abccaae", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/27 [00:00 7\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43ms\u001b[49m\u001b[38;5;241m.\u001b[39mpost(\n\u001b[1;32m 8\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhttp://localhost:8000/upsert\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 9\u001b[0m \n\u001b[1;32m 10\u001b[0m headers \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 11\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAuthorization\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mBearer \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mBEARER_TOKEN\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 12\u001b[0m },\n\u001b[1;32m 13\u001b[0m \n\u001b[1;32m 14\u001b[0m json \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 15\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdocuments\u001b[39m\u001b[38;5;124m\"\u001b[39m: documents[i:i_end]\n\u001b[1;32m 16\u001b[0m }\n\u001b[1;32m 17\u001b[0m )\n", - "\u001b[0;31mNameError\u001b[0m: name 's' is not defined" - ] - } - ], + "outputs": [], "source": [ "batchSize = 100\n", "\n", @@ -410,17 +231,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[{'query': 'What is the third part of the death penalty process?'}, {'query': 'Name one of the Panglong Conference negotiators who had a professional title.'}, {'query': 'How did Myanmar increase their rating by 1?'}, {'query': 'How are nats paid tribute to in Bamar culture?'}, {'query': 'When did the military begin its transition?'}]\n" - ] - } - ], + "outputs": [], "source": [ "# extract questions and reformat into queries\n", "queries = data['question'].tolist()\n", @@ -442,17 +255,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], + "outputs": [], "source": [ "# query the vector database\n", "results = requests.post(\n", @@ -479,81 +284,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "QUERY:\n", - "When was the half dollar last issued by the government?\n", - "\n", - "CONTEXT:\n", - "0.33: The Gold Standard Act of 1900 abandoned the bimetallic standard and defined the dollar as 23.22 grains (1.505 g) of gold, equivalent to setting the price of 1 troy ounce of gold at $20.67. Silver coins continued to be issued for circulation until 1964, when all silver was removed from dimes and quarters, and the half dollar was reduced to 40% silver. Silver half dollars were last issued for circulation in 1970. Gold coins were confiscated by Executive Order 6102 issued in 1933 by Franklin Roosevelt. The gold standard was changed to 13.71 grains (0.888 g), equivalent to setting the price of 1 troy ounce of gold at $35. This standard persisted until 1968.\n", - "0.34: Early releases of the Washington coin included error coins shipped primarily from the Philadelphia mint to Florida and Tennessee banks. Highly sought after by collectors, and trading for as much as $850 each within a week of discovery, the error coins were identified by the absence of the edge impressions \"E PLURIBUS UNUM IN GOD WE TRUST 2007 P\". The mint of origin is generally accepted to be mostly Philadelphia, although identifying the source mint is impossible without opening a mint pack also containing marked units. Edge lettering is minted in both orientations with respect to \"heads\", some amateur collectors were initially duped into buying \"upside down lettering error\" coins. Some cynics also erroneously point out that the Federal Reserve makes more profit from dollar bills than dollar coins because they wear out in a few years, whereas coins are more permanent.\n", - "0.35: Currently printed denominations are $1, $2, $5, $10, $20, $50, and $100. Notes above the $100 denomination stopped being printed in 1946 and were officially withdrawn from circulation in 1969. These notes were used primarily in inter-bank transactions or by organized crime; it was the latter usage that prompted President Richard Nixon to issue an executive order in 1969 halting their use. With the advent of electronic banking, they became less necessary. Notes in denominations of $500, $1,000, $5,000, $10,000 and $100,000 were all produced at one time; see large denomination bills in U.S. currency for details. These notes are now collectors' items and are worth more than their face value to collectors.\n", - "\n", - "RESPONSE: \n", - "The half dollar was last issued for circulation by the government in 1970.\n", - "\n", - "----------------------------------------------------------------------\n", - "\n", - "QUERY:\n", - "How were some collectors fooled when seeking error coins?\n", - "\n", - "CONTEXT:\n", - "0.27: Early releases of the Washington coin included error coins shipped primarily from the Philadelphia mint to Florida and Tennessee banks. Highly sought after by collectors, and trading for as much as $850 each within a week of discovery, the error coins were identified by the absence of the edge impressions \"E PLURIBUS UNUM IN GOD WE TRUST 2007 P\". The mint of origin is generally accepted to be mostly Philadelphia, although identifying the source mint is impossible without opening a mint pack also containing marked units. Edge lettering is minted in both orientations with respect to \"heads\", some amateur collectors were initially duped into buying \"upside down lettering error\" coins. Some cynics also erroneously point out that the Federal Reserve makes more profit from dollar bills than dollar coins because they wear out in a few years, whereas coins are more permanent.\n", - "0.4: The fallacy of this argument arises because new notes printed to replace worn out notes, which have been withdrawn from circulation, bring in no net revenue to the government to offset the costs of printing new notes and destroying the old ones. As most vending machines are incapable of making change in banknotes, they commonly accept only $1 bills, though a few will give change in dollar coins.\n", - "0.42: In 1982, the US Mint began minting pennies coated in copper but made primarily of zinc. With the new zinc pennies, there is the potential for zinc toxicosis, which can be fatal. One reported case of chronic ingestion of 425 pennies (over 1 kg of zinc) resulted in death due to gastrointestinal bacterial and fungal sepsis, whereas another patient, who ingested 12 grams of zinc, only showed lethargy and ataxia (gross lack of coordination of muscle movements). Several other cases have been reported of humans suffering zinc intoxication by the ingestion of zinc coins.\n", - "\n", - "RESPONSE: \n", - "Some collectors were initially fooled when seeking error coins because some of the early releases of the Washington coin included error coins with edge lettering minted in both orientations with respect to \"heads\". This led some amateur collectors to mistakenly believe that the \"upside down lettering\" was an error, when in fact it was a normal variation.\n", - "\n", - "----------------------------------------------------------------------\n", - "\n", - "QUERY:\n", - "What conclusion was drawn by the Phillips curve?\n", - "\n", - "CONTEXT:\n", - "0.36: In his Prices and Production (1931), Hayek argued that the business cycle resulted from the central bank's inflationary credit expansion and its transmission over time, leading to a capital misallocation caused by the artificially low interest rates. Hayek claimed that \"the past instability of the market economy is the consequence of the exclusion of the most important regulator of the market mechanism, money, from itself being regulated by the market process\".\n", - "0.38: The value of the U.S. dollar was therefore no longer anchored to gold, and it fell upon the Federal Reserve to maintain the value of the U.S. currency. The Federal Reserve, however, continued to increase the money supply, resulting in stagflation and a rapidly declining value of the U.S. dollar in the 1970s. This was largely due to the prevailing economic view at the time that inflation and real economic growth were linked (the Phillips curve), and so inflation was regarded as relatively benign. Between 1965 and 1981, the U.S. dollar lost two thirds of its value.\n", - "0.4: Hayek's principal investigations in economics concerned capital, money, and the business cycle. Mises had earlier applied the concept of marginal utility to the value of money in his Theory of Money and Credit (1912), in which he also proposed an explanation for \"industrial fluctuations\" based on the ideas of the old British Currency School and of Swedish economist Knut Wicksell. Hayek used this body of work as a starting point for his own interpretation of the business cycle, elaborating what later became known as the \"Austrian Theory of the Business Cycle\". Hayek spelled out the Austrian approach in more detail in his book, published in 1929, an English translation of which appeared in 1933 as Monetary Theory and the Trade Cycle. There he argued for a monetary approach to the origins of the cycle.\n", - "\n", - "RESPONSE: \n", - "The Phillips curve, which was developed by economist A. W. Phillips, suggested a trade-off between inflation and unemployment. It concluded that there was an inverse relationship between the two variables, implying that as unemployment decreased, inflation would increase and vice versa. This view was widely accepted during the 1960s and 1970s, leading policymakers to believe that they could manipulate inflation and unemployment through fiscal and monetary policy. However, this view was challenged by the stagflation experience of the 1970\n", - "\n", - "----------------------------------------------------------------------\n", - "\n", - "QUERY:\n", - "How did the motors being expensive reflect on the American inventor?\n", - "\n", - "CONTEXT:\n", - "0.32: The first commutator DC electric motor capable of turning machinery was invented by the British scientist William Sturgeon in 1832. Following Sturgeon's work, a commutator-type direct-current electric motor made with the intention of commercial use was built by the American inventor Thomas Davenport, which he patented in 1837. The motors ran at up to 600 revolutions per minute, and powered machine tools and a printing press. Due to the high cost of primary battery power, the motors were commercially unsuccessful and Davenport went bankrupt. Several inventors followed Sturgeon in the development of DC motors but all encountered the same battery power cost issues. No electricity distribution had been developed at the time. Like Sturgeon's motor, there was no practical commercial market for these motors.\n", - "0.38: Induction motor improvements flowing from these inventions and innovations were such that a 100 horsepower (HP) induction motor currently has the same mounting dimensions as a 7.5 HP motor in 1897.\n", - "0.38: In 1824, the French physicist François Arago formulated the existence of rotating magnetic fields, termed Arago's rotations, which, by manually turning switches on and off, Walter Baily demonstrated in 1879 as in effect the first primitive induction motor. In the 1880s, many inventors were trying to develop workable AC motors because AC's advantages in long-distance high-voltage transmission were counterbalanced by the inability to operate motors on AC. The first alternating-current commutatorless induction motors were independently invented by Galileo Ferraris and Nikola Tesla, a working motor model having been demonstrated by the former in 1885 and by the latter in 1887. In 1888, the Royal Academy of Science of Turin published Ferraris' research detailing the foundations of motor operation while however concluding that \"the apparatus based on that principle could not be of any commercial importance as motor.\n", - "\n", - "RESPONSE: \n", - "The high cost of primary battery power for the motors developed by the American inventor Thomas Davenport reflected negatively on him. Despite his invention of a commutator-type direct-current electric motor and obtaining a patent in 1837, the motors were commercially unsuccessful because they were expensive to operate. As a result, Davenport went bankrupt, as the motors did not find a practical commercial market due to the high cost of power.\n", - "\n", - "----------------------------------------------------------------------\n", - "\n", - "QUERY:\n", - "stepper motors contains?\n", - "\n", - "CONTEXT:\n", - "0.29: Stepper motors are a type of motor frequently used when precise rotations are required. In a stepper motor an internal rotor containing PMs or a magnetically soft rotor with salient poles is controlled by a set of external magnets that are switched electronically. A stepper motor may also be thought of as a cross between a DC electric motor and a rotary solenoid. As each coil is energized in turn, the rotor aligns itself with the magnetic field produced by the energized field winding. Unlike a synchronous motor, in its application, the stepper motor may not rotate continuously; instead, it \"steps\"—starts and then quickly stops again—from one position to the next as field windings are energized and de-energized in sequence. Depending on the sequence, the rotor may turn forwards or backwards, and it may change direction, stop, speed up or slow down arbitrarily at any time.\n", - "0.34: Stepper motors were and still are often used in computer printers, optical scanners, and digital photocopiers to move the optical scanning element, the print head carriage (of dot matrix and inkjet printers), and the platen or feed rollers. Likewise, many computer plotters (which since the early 1990s have been replaced with large-format inkjet and laser printers) used rotary stepper motors for pen and platen movement; the typical alternatives here were either linear stepper motors or servomotors with closed-loop analog control systems.\n", - "0.39: A servo system differs from some stepper motor applications in that the position feedback is continuous while the motor is running; a stepper system relies on the motor not to \"miss steps\" for short term accuracy, although a stepper system may include a \"home\" switch or other element to provide long-term stability of control. For instance, when a typical dot matrix computer printer starts up, its controller makes the print head stepper motor drive to its left-hand limit, where a position sensor defines home position and stops stepping. As long as power is on, a bidirectional counter in the printer's microprocessor keeps track of print-head position.\n", - "\n", - "RESPONSE: \n", - "Stepper motors contain an internal rotor that can have permanent magnets or salient poles. They are controlled by a set of external magnets that are switched electronically. The motor operates by aligning the rotor with the magnetic field produced by the energized field winding. Stepper motors can rotate in either direction, change direction, stop, speed up, or slow down arbitrarily at any time.\n", - "\n", - "----------------------------------------------------------------------\n" - ] - } - ], + "outputs": [], "source": [ "# iterate through each set of queries/results\n", "for query_response in results.json()['results']:\n", @@ -615,7 +348,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -635,7 +368,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, diff --git a/examples/providers/kdbai/kdbai-chatgpt-overview.png b/examples/providers/kdbai/kdbai-chatgpt-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..f323a1076d595fc1640c2a4161a2c2cc0763cd43 GIT binary patch literal 90715 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 JTVm{Z`+pfM`Zxdp literal 0 HcmV?d00001 From 266822471c5c6230e5d09d52cd2618cacbac2497 Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Tue, 12 Sep 2023 15:35:17 +0100 Subject: [PATCH 22/28] improved diagram --- .../kdbai/kdbai-chatgpt-overview.png | Bin 90715 -> 65123 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/providers/kdbai/kdbai-chatgpt-overview.png b/examples/providers/kdbai/kdbai-chatgpt-overview.png index f323a1076d595fc1640c2a4161a2c2cc0763cd43..c9299c1d7ead2b686034742e0386fe8464f5c76d 100644 GIT binary patch literal 65123 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 JTVm{Z`+pfM`Zxdp From eda7960236cc7cce1223ea6c32e5425293e29fba Mon Sep 17 00:00:00 2001 From: Charli Posner Date: Wed, 13 Sep 2023 14:55:15 +0100 Subject: [PATCH 23/28] KDB.AI notebook with examples --- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 283 +++++++++++++++++- .../kdbai/kdbai-chatgpt-overview.png | Bin 65123 -> 52843 bytes 2 files changed, 267 insertions(+), 16 deletions(-) diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index 727a7e090..f6969b194 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -100,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -116,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -134,9 +134,137 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of unique contexts: 2648\n" + ] + }, + { + "data": { + "text/html": [ + "

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtitlecontextquestionanswersmetadata
07ba1e8f4261d3170fcf42e84a81dd749116fae95BrainAnother approach to brain function is to exami...What sare the benifts of the blood brain barrir?{'text': ['isolated from the bloodstream'], 'a...{'split': 'train', 'model_in_the_loop': 'Combi...
12936a8460bfffe437b54cf3ec1e825a3b7b5627a1BrainMotor systems are areas of the brain that are ...What do you think with?{'text': ['brain'], 'answer_start': [467]}{'split': 'train', 'model_in_the_loop': 'Combi...
24e40737d487964dbcd26a223f2799cf56390a98a8BrainThe brain is an organ that serves as the cente...How are neurons connected?{'text': ['synapses'], 'answer_start': [602]}{'split': 'train', 'model_in_the_loop': 'Combi...
37a0f8e785a10f6e21e24207d24ba2823162383062BrainThe SCN projects to a set of areas in the hypo...The body's central biological clock is contain...{'text': ['SCN'], 'answer_start': [4]}{'split': 'train', 'model_in_the_loop': 'Combi...
536d753d4a8878b5f5bc496d9a369b8c0b212079a0BrainThe brain contains several motor areas that pr...What is at the highest level?{'text': ['the primary motor cortex'], 'answer...{'split': 'train', 'model_in_the_loop': 'Combi...
\n", + "
" + ], + "text/plain": [ + " id title \\\n", + "0 7ba1e8f4261d3170fcf42e84a81dd749116fae95 Brain \n", + "12 936a8460bfffe437b54cf3ec1e825a3b7b5627a1 Brain \n", + "24 e40737d487964dbcd26a223f2799cf56390a98a8 Brain \n", + "37 a0f8e785a10f6e21e24207d24ba2823162383062 Brain \n", + "53 6d753d4a8878b5f5bc496d9a369b8c0b212079a0 Brain \n", + "\n", + " context \\\n", + "0 Another approach to brain function is to exami... \n", + "12 Motor systems are areas of the brain that are ... \n", + "24 The brain is an organ that serves as the cente... \n", + "37 The SCN projects to a set of areas in the hypo... \n", + "53 The brain contains several motor areas that pr... \n", + "\n", + " question \\\n", + "0 What sare the benifts of the blood brain barrir? \n", + "12 What do you think with? \n", + "24 How are neurons connected? \n", + "37 The body's central biological clock is contain... \n", + "53 What is at the highest level? \n", + "\n", + " answers \\\n", + "0 {'text': ['isolated from the bloodstream'], 'a... \n", + "12 {'text': ['brain'], 'answer_start': [467]} \n", + "24 {'text': ['synapses'], 'answer_start': [602]} \n", + "37 {'text': ['SCN'], 'answer_start': [4]} \n", + "53 {'text': ['the primary motor cortex'], 'answer... \n", + "\n", + " metadata \n", + "0 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "12 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "24 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "37 {'split': 'train', 'model_in_the_loop': 'Combi... \n", + "53 {'split': 'train', 'model_in_the_loop': 'Combi... " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "data = load_dataset(\"adversarial_qa\", 'adversarialQA', split=\"train\").to_pandas()\n", "data = data.drop_duplicates(subset=[\"context\"])\n", @@ -153,9 +281,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'text': 'Another approach to brain function is to examine the consequences of '\n", + " 'damage to specific brain areas. Even though it is protected by the '\n", + " 'skull and meninges, surrounded by cerebrospinal fluid, and isolated '\n", + " 'from the bloodstream by the blood–brain barrier, the delicate nature '\n", + " 'of the brain makes it vulnerable to numerous diseases and several '\n", + " 'types of damage. In humans, the effects of strokes and other types '\n", + " 'of brain damage have been a key source of information about brain '\n", + " 'function. Because there is no ability to experimentally control the '\n", + " 'nature of the damage, however, this information is often difficult '\n", + " 'to interpret. In animal studies, most commonly involving rats, it is '\n", + " 'possible to use electrodes or locally injected chemicals to produce '\n", + " 'precise patterns of damage and then examine the consequences for '\n", + " 'behavior.'}\n" + ] + } + ], "source": [ "# extract text data from the dataset\n", "documents = [\n", @@ -175,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -192,9 +340,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "84c4cdf4852344b48df3da65fbb9fe3f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/27 [00:00\n" + ] + } + ], "source": [ "# query the vector database\n", "results = requests.post(\n", @@ -284,9 +463,81 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "QUERY:\n", + "The man who proposed horse powered trams was not associated with what?\n", + "\n", + "CONTEXT:\n", + "0.31: Within the city there have been two tram networks in operation. A proposal to develop a horse-drawn tram (linking the city's railway termini) was made by American George Francis Train in the 1860s, and implemented in 1872 by the Cork Tramway Company. However, the company ceased trading in 1875 after Cork Corporation refused permission to extend the line, mainly because of objections from cab operators to the type of tracks which – although they were laid to the Irish national railway gauge of 5 ft 3in – protruded from the road surface.\n", + "0.39: Some street trams (streetcars) used conduit third-rail current collection. The third rail was below street level. The tram picked up the current through a plough (U.S. \"plow\") accessed through a narrow slot in the road. In the United States, much (though not all) of the former streetcar system in Washington, D.C. (discontinued in 1962) was operated in this manner to avoid the unsightly wires and poles associated with electric traction. The same was true with Manhattan's former streetcar system. The evidence of this mode of running can still be seen on the track down the slope on the northern access to the abandoned Kingsway Tramway Subway in central London, United Kingdom, where the slot between the running rails is clearly visible, and on P and Q Streets west of Wisconsin Avenue in the Georgetown neighborhood of Washington DC, where the abandoned tracks have not been paved over.\n", + "0.42: Steadfast in his promotion of three-phase development, Mikhail Dolivo-Dobrovolsky invented the three-phase cage-rotor induction motor in 1889 and the three-limb transformer in 1890. This type of motor is now used for the vast majority of commercial applications. However, he claimed that Tesla's motor was not practical because of two-phase pulsations, which prompted him to persist in his three-phase work. Although Westinghouse achieved its first practical induction motor in 1892 and developed a line of polyphase 60 hertz induction motors in 1893, these early Westinghouse motors were two-phase motors with wound rotors until B. G. Lamme developed a rotating bar winding rotor. The General Electric Company began developing three-phase induction motors in 1891. By 1896, General Electric and Westinghouse signed a cross-licensing agreement for the bar-winding-rotor design, later called the squirrel-cage rotor.\n", + "\n", + "RESPONSE: \n", + "The man who proposed horse-powered trams, George Francis Train, was not associated with the invention of the three-phase cage-rotor induction motor or the development of electric trams using conduit third-rail current collection.\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "Cillian Murphy performed?\n", + "\n", + "CONTEXT:\n", + "0.39: The Cork School of Music and the Crawford College of Art and Design provide a throughput of new blood, as do the active theatre components of several courses at University College Cork (UCC). Highlights include: Corcadorca Theatre Company, of which Cillian Murphy was a troupe member prior to Hollywood fame; the Institute for Choreography and Dance, a national contemporary dance resource;[citation needed] the Triskel Arts Centre (capacity c.90), which includes the Triskel Christchurch independent cinema; dance venue the Firkin Crane (capacity c.240); the Cork Academy of Dramatic Art (CADA) and Graffiti Theatre Company; and the Cork Jazz Festival, Cork Film Festival, and Live at the Marquee events. The Everyman Palace Theatre (capacity c.650) and the Granary Theatre (capacity c.150) both play host to dramatic plays throughout the year.\n", + "0.45: In India, it was reported that the Indian Central Board of Film Certification (CBFC) censored kissing scenes featuring Monica Bellucci, Daniel Craig, and Léa Seydoux. They also muted all profanity. This prompted criticism of the board online, especially on Twitter.\n", + "0.45: McGuinness Flint, for whom Graham Lyle played the mandolin on their most successful single, When I'm Dead And Gone, is another example. Lyle was also briefly a member of Ronnie Lane's Slim Chance, and played mandolin on their hit How Come. One of the more prominent early mandolin players in popular music was Robin Williamson in The Incredible String Band. Ian Anderson of Jethro Tull is a highly accomplished mandolin player (beautiful track Pussy Willow), as is his guitarist Martin Barre. The popular song Please Please Please Let Me Get What I Want by The Smiths featured a mandolin solo played by Johnny Marr. More recently, the Glasgow-based band Sons and Daughters featured the mandolin, played by Ailidh Lennon, on tracks such as Fight, Start to End, and Medicine. British folk-punk icons the Levellers also regularly use the mandolin in their songs.\n", + "\n", + "RESPONSE: \n", + "Cillian Murphy, before achieving fame in Hollywood, performed as a troupe member with the Corcadorca Theatre Company in Cork, Ireland.\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "What kind of weather does Cork get?\n", + "\n", + "CONTEXT:\n", + "0.2: The climate of Cork, like the rest of Ireland, is mild and changeable with abundant rainfall and a lack of temperature extremes. Cork lies in plant Hardiness zone 9b. Met Éireann maintains a climatological weather station at Cork Airport, a few kilometres south of the city. It should be noted that the airport is at an altitude of 151 metres (495 ft) and temperatures can often differ by a few degrees between the airport and the city itself. There are also smaller synoptic weather stations at UCC and Clover Hill.\n", + "0.22: Cork is also a generally foggy city, with an average of 97 days of fog a year, most common during mornings and during winter. Despite this, however, Cork is also one of Ireland's sunniest cities, with an average of 3.9 hours of sunshine every day and only having 67 days where there is no \"recordable sunshine\", mostly during and around winter.\n", + "0.25: Temperatures below 0 °C (32 °F) or above 25 °C (77 °F) are rare. Cork Airport records an average of 1,227.9 millimetres (4.029 ft) of precipitation annually, most of which is rain. The airport records an average of 7 days of hail and 11 days of snow or sleet a year; though it only records lying snow for 2 days of the year. The low altitude of the city, and moderating influences of the harbour, mean that lying snow very rarely occurs in the city itself. There are on average 204 \"rainy\" days a year (over 0.2 millimetres (0.0079 in) of rainfall), of which there are 73 days with \"heavy rain\" (over 5 millimetres (0.20 in)).\n", + "\n", + "RESPONSE: \n", + "Cork experiences a mild and changeable climate with abundant rainfall and a lack of temperature extremes. The city is generally foggy, with an average of 97 days of fog per year, most common during mornings and winter. Cork is also one of Ireland's sunniest cities, with an average of 3.9 hours of sunshine per day. Temperature extremes below 0 °C (32 °F) or above 25 °C (77 °F) are rare. The city receives an\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "Which of the following is not a song: I Want It All, The Invisible Man, or The Miracle?\n", + "\n", + "CONTEXT:\n", + "0.33: After working on various solo projects during 1988 (including Mercury's collaboration with Montserrat Caballé, Barcelona), the band released The Miracle in 1989. The album continued the direction of A Kind of Magic, using a pop-rock sound mixed with a few heavy numbers. It spawned the European hits \"I Want It All\", \"Breakthru\", \"The Invisible Man\", \"Scandal\", and \"The Miracle\". The Miracle also began a change in direction of Queen's songwriting philosophy. Since the band's beginning, nearly all songs had been written by and credited to a single member, with other members adding minimally. With The Miracle, the band's songwriting became more collaborative, and they vowed to credit the final product only to Queen as a group.\n", + "0.45: Others found renewed success in the singles charts with power ballads, including REO Speedwagon with \"Keep on Loving You\" (1980) and \"Can't Fight This Feeling\" (1984), Journey with \"Don't Stop Believin'\" (1981) and \"Open Arms\" (1982), Foreigner's \"I Want to Know What Love Is\", Scorpions' \"Still Loving You\" (both from 1984), Heart’s \"What About Love\" (1985) and \"These Dreams\" (1986), and Boston's \"Amanda\" (1986).\n", + "0.47: Certain staples of classical music are often used commercially (either in advertising or in movie soundtracks). In television commercials, several passages have become clichéd, particularly the opening of Richard Strauss' Also sprach Zarathustra (made famous in the film 2001: A Space Odyssey) and the opening section \"O Fortuna\" of Carl Orff's Carmina Burana, often used in the horror genre; other examples include the Dies Irae from the Verdi Requiem, Edvard Grieg's In the Hall of the Mountain King from Peer Gynt, the opening bars of Beethoven's Symphony No. 5, Wagner's Ride of the Valkyries from Die Walküre, Rimsky-Korsakov's Flight of the Bumblebee, and excerpts of Aaron Copland's Rodeo.\n", + "\n", + "RESPONSE: \n", + "Based on my knowledge, \"The Miracle\" is not a song. \"I Want It All\" and \"The Invisible Man\" are both songs by Queen.\n", + "\n", + "----------------------------------------------------------------------\n", + "\n", + "QUERY:\n", + "What is Milton Keynes last name?\n", + "\n", + "CONTEXT:\n", + "0.46: Other notable Old Etonians include scientists Robert Boyle, John Maynard Smith, J. B. S. Haldane, Stephen Wolfram and the 2012 Nobel Prize in Physiology or Medicine winner, John Gurdon; Beau Brummell; economists John Maynard Keynes and Richard Layard; Antarctic explorer Lawrence Oates; politician Alan Clark; entrepreneur, charity organiser and partner of Adele, Simon Konecki; cricket commentator Henry Blofeld; explorer Sir Ranulph Fiennes; adventurer Bear Grylls; composers Thomas Arne, George Butterworth, Roger Quilter, Frederick Septimus Kelly, Donald Tovey, Thomas Dunhill, Lord Berners, Victor Hely-Hutchinson, and Peter Warlock (Philip Heseltine); Hubert Parry, who wrote the song Jerusalem and the coronation anthem I was glad; and musicians Frank Turner and Humphrey Lyttelton.\n", + "0.48: In June 1990, The Times ceased its policy of using courtesy titles (\"Mr\", \"Mrs\", or \"Miss\" prefixes) for living persons before full names on first reference, but it continues to use them before surnames on subsequent references. The more formal style is now confined to the \"Court and Social\" page, though \"Ms\" is now acceptable in that section, as well as before surnames in news sections.\n", + "0.49: In 1762, George III acquired Buckingham House and it was enlarged over the next 75 years. During the 18th century, London was dogged by crime, and the Bow Street Runners were established in 1750 as a professional police force. In total, more than 200 offences were punishable by death, including petty theft. Most children born in the city died before reaching their third birthday. The coffeehouse became a popular place to debate ideas, with growing literacy and the development of the printing press making news widely available; and Fleet Street became the centre of the British press.\n", + "\n", + "RESPONSE: \n", + "Based on my knowledge, Milton Keynes does not have a last name. However, if you are referring to the town of Milton Keynes in Buckinghamshire, England, it is named after the existing villages of Milton Keynes, Bletchley, and Wolverton.\n", + "\n", + "----------------------------------------------------------------------\n" + ] + } + ], "source": [ "# iterate through each set of queries/results\n", "for query_response in results.json()['results']:\n", @@ -348,7 +599,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ diff --git a/examples/providers/kdbai/kdbai-chatgpt-overview.png b/examples/providers/kdbai/kdbai-chatgpt-overview.png index c9299c1d7ead2b686034742e0386fe8464f5c76d..bce69d96aa2d2b4ea33a9641e55a0389bd6bbfc3 100644 GIT binary patch literal 52843 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 h`TvyAym?#yAhb7 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 Date: Thu, 9 Nov 2023 15:15:42 +0100 Subject: [PATCH 24/28] Fix pyproject.toml and refresh poetry.lock. --- poetry.lock | 23 +++++++++-------------- pyproject.toml | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index 17ebbe223..a71f5332e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "aiohttp" @@ -249,13 +249,13 @@ msal-extensions = ">=0.3.0,<2.0.0" [[package]] name = "azure-search-documents" -version = "11.4.0a20230509004" +version = "11.4.0b8" description = "Microsoft Azure Cognitive Search Client Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "azure-search-documents-11.4.0a20230509004.zip", hash = "sha256:6cca144573161a10aa0fcd13927264453e79c63be6a53cf2ec241c9c8c22f6b5"}, - {file = "azure_search_documents-11.4.0a20230509004-py3-none-any.whl", hash = "sha256:6215e9a4f9e935ff3eac1b7d5519c6c0789b4497eb11242d376911aaefbb0359"}, + {file = "azure-search-documents-11.4.0b8.zip", hash = "sha256:b178ff52918590191a9cb7f411a9ab3cb517663666a501a3e84b715d19b0d93b"}, + {file = "azure_search_documents-11.4.0b8-py3-none-any.whl", hash = "sha256:4137daa2db75bff9484d394c16c0604822a51281cad2f50e11d7c48dd8d4b4cf"}, ] [package.dependencies] @@ -263,11 +263,6 @@ azure-common = ">=1.1,<2.0" azure-core = ">=1.24.0,<2.0.0" isodate = ">=0.6.0" -[package.source] -type = "legacy" -url = "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple" -reference = "azure-sdk-dev" - [[package]] name = "backoff" version = "2.2.1" @@ -1655,17 +1650,17 @@ trio = ["async_generator", "trio"] [[package]] name = "kdbai-client" -version = "0.0.0.dev5" +version = "0.1.1" description = "KDB.AI Client for Python" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "kdbai_client-0.0.0.dev5-py3-none-any.whl", hash = "sha256:1895176f2d9de4a38e65a3b4d4eedfc993a0ffd30b927f27aa1f344593d6e176"}, + {file = "kdbai_client-0.1.1-py3-none-any.whl", hash = "sha256:c0ba72ede4ac755eb889510939ed7f6c91d345c59d02ee9eb44905b9cc171d2d"}, ] [package.dependencies] -pandas = ">=1.5.0" -pykx = ">=1.6.0" +pandas = ">=1.5.0,<2.0.0" +pykx = ">=1.6.3,<2.0.0" [package.extras] lint = ["mypy", "mypy-gitlab-code-quality"] @@ -4313,4 +4308,4 @@ postgresql = ["psycopg2cffi"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "7cdc74ff49f9b4d0631152e7350f46f3ac2ebccde20d37d1b7c1c31560d8e114" +content-hash = "36aaf72a155d0a49597c4deb908e45c9ba23ed737cc4aa53117e5f458fec7736" diff --git a/pyproject.toml b/pyproject.toml index 8452ebf89..6a12d36fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ psycopg2cffi = {version = "^2.9.0", optional = true} loguru = "^0.7.0" elasticsearch = "8.8.2" pykx = "^1.6.3" -kdbai-client = "^0.1.1" +kdbai_client = "^0.1.1" [tool.poetry.scripts] start = "server.main:start" From 5878832e64b0ed564918f2eccef52ab664593604 Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Thu, 9 Nov 2023 15:36:17 +0100 Subject: [PATCH 25/28] Upgrade the sample KDB.AI notebook to the new OpenAI API. --- .../providers/kdbai/ChatGPT_QA_Demo.ipynb | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index f6969b194..813c5960d 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -346,7 +346,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "84c4cdf4852344b48df3da65fbb9fe3f", + "model_id": "bbcc7b88e39a49039d3983aae95a2b3d", "version_major": 2, "version_minor": 0 }, @@ -394,14 +394,14 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[{'query': 'The man who proposed horse powered trams was not associated with what?'}, {'query': 'Cillian Murphy performed?'}, {'query': 'What kind of weather does Cork get?'}, {'query': 'Which of the following is not a song: I Want It All, The Invisible Man, or The Miracle?'}, {'query': 'What is Milton Keynes last name?'}]\n" + "[{'query': 'What roads are part of the Schnellweg?'}, {'query': 'Little Britain is actually?'}, {'query': 'What is the second smallest large urban area listed?'}, {'query': 'Which country is governed by a national assembly?'}, {'query': 'What was Ireland an exception to?'}]\n" ] } ], @@ -426,7 +426,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -463,7 +463,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -472,67 +472,67 @@ "text": [ "\n", "QUERY:\n", - "The man who proposed horse powered trams was not associated with what?\n", + "What roads are part of the Schnellweg?\n", "\n", "CONTEXT:\n", - "0.31: Within the city there have been two tram networks in operation. A proposal to develop a horse-drawn tram (linking the city's railway termini) was made by American George Francis Train in the 1860s, and implemented in 1872 by the Cork Tramway Company. However, the company ceased trading in 1875 after Cork Corporation refused permission to extend the line, mainly because of objections from cab operators to the type of tracks which – although they were laid to the Irish national railway gauge of 5 ft 3in – protruded from the road surface.\n", - "0.39: Some street trams (streetcars) used conduit third-rail current collection. The third rail was below street level. The tram picked up the current through a plough (U.S. \"plow\") accessed through a narrow slot in the road. In the United States, much (though not all) of the former streetcar system in Washington, D.C. (discontinued in 1962) was operated in this manner to avoid the unsightly wires and poles associated with electric traction. The same was true with Manhattan's former streetcar system. The evidence of this mode of running can still be seen on the track down the slope on the northern access to the abandoned Kingsway Tramway Subway in central London, United Kingdom, where the slot between the running rails is clearly visible, and on P and Q Streets west of Wisconsin Avenue in the Georgetown neighborhood of Washington DC, where the abandoned tracks have not been paved over.\n", - "0.42: Steadfast in his promotion of three-phase development, Mikhail Dolivo-Dobrovolsky invented the three-phase cage-rotor induction motor in 1889 and the three-limb transformer in 1890. This type of motor is now used for the vast majority of commercial applications. However, he claimed that Tesla's motor was not practical because of two-phase pulsations, which prompted him to persist in his three-phase work. Although Westinghouse achieved its first practical induction motor in 1892 and developed a line of polyphase 60 hertz induction motors in 1893, these early Westinghouse motors were two-phase motors with wound rotors until B. G. Lamme developed a rotating bar winding rotor. The General Electric Company began developing three-phase induction motors in 1891. By 1896, General Electric and Westinghouse signed a cross-licensing agreement for the bar-winding-rotor design, later called the squirrel-cage rotor.\n", + "0.21: The Schnellweg (en: expressway) system, a number of Bundesstraße roads, forms a structure loosely resembling a large ring road together with A2 and A7. The roads are B 3, B 6 and B 65, called Westschnellweg (B6 on the northern part, B3 on the southern part), Messeschnellweg (B3, becomes A37 near Burgdorf, crosses A2, becomes B3 again, changes to B6 at Seelhorster Kreuz, then passes the Hanover fairground as B6 and becomes A37 again before merging into A7) and Südschnellweg (starts out as B65, becomes B3/B6/B65 upon crossing Westschnellweg, then becomes B65 again at Seelhorster Kreuz).\n", + "0.21: The Schnellweg (en: expressway) system, a number of Bundesstraße roads, forms a structure loosely resembling a large ring road together with A2 and A7. The roads are B 3, B 6 and B 65, called Westschnellweg (B6 on the northern part, B3 on the southern part), Messeschnellweg (B3, becomes A37 near Burgdorf, crosses A2, becomes B3 again, changes to B6 at Seelhorster Kreuz, then passes the Hanover fairground as B6 and becomes A37 again before merging into A7) and Südschnellweg (starts out as B65, becomes B3/B6/B65 upon crossing Westschnellweg, then becomes B65 again at Seelhorster Kreuz).\n", + "0.21: The Schnellweg (en: expressway) system, a number of Bundesstraße roads, forms a structure loosely resembling a large ring road together with A2 and A7. The roads are B 3, B 6 and B 65, called Westschnellweg (B6 on the northern part, B3 on the southern part), Messeschnellweg (B3, becomes A37 near Burgdorf, crosses A2, becomes B3 again, changes to B6 at Seelhorster Kreuz, then passes the Hanover fairground as B6 and becomes A37 again before merging into A7) and Südschnellweg (starts out as B65, becomes B3/B6/B65 upon crossing Westschnellweg, then becomes B65 again at Seelhorster Kreuz).\n", "\n", "RESPONSE: \n", - "The man who proposed horse-powered trams, George Francis Train, was not associated with the invention of the three-phase cage-rotor induction motor or the development of electric trams using conduit third-rail current collection.\n", + "The roads that are part of the Schnellweg system are B3, B6, and B65. Specifically, the Westschnellweg consists of B6 on the northern part and B3 on the southern part, the Messeschnellweg includes B3/A37, and the Südschnellweg includes B65/B3/B6/B65 sections.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "Cillian Murphy performed?\n", + "Little Britain is actually?\n", "\n", "CONTEXT:\n", - "0.39: The Cork School of Music and the Crawford College of Art and Design provide a throughput of new blood, as do the active theatre components of several courses at University College Cork (UCC). Highlights include: Corcadorca Theatre Company, of which Cillian Murphy was a troupe member prior to Hollywood fame; the Institute for Choreography and Dance, a national contemporary dance resource;[citation needed] the Triskel Arts Centre (capacity c.90), which includes the Triskel Christchurch independent cinema; dance venue the Firkin Crane (capacity c.240); the Cork Academy of Dramatic Art (CADA) and Graffiti Theatre Company; and the Cork Jazz Festival, Cork Film Festival, and Live at the Marquee events. The Everyman Palace Theatre (capacity c.650) and the Granary Theatre (capacity c.150) both play host to dramatic plays throughout the year.\n", - "0.45: In India, it was reported that the Indian Central Board of Film Certification (CBFC) censored kissing scenes featuring Monica Bellucci, Daniel Craig, and Léa Seydoux. They also muted all profanity. This prompted criticism of the board online, especially on Twitter.\n", - "0.45: McGuinness Flint, for whom Graham Lyle played the mandolin on their most successful single, When I'm Dead And Gone, is another example. Lyle was also briefly a member of Ronnie Lane's Slim Chance, and played mandolin on their hit How Come. One of the more prominent early mandolin players in popular music was Robin Williamson in The Incredible String Band. Ian Anderson of Jethro Tull is a highly accomplished mandolin player (beautiful track Pussy Willow), as is his guitarist Martin Barre. The popular song Please Please Please Let Me Get What I Want by The Smiths featured a mandolin solo played by Johnny Marr. More recently, the Glasgow-based band Sons and Daughters featured the mandolin, played by Ailidh Lennon, on tracks such as Fight, Start to End, and Medicine. British folk-punk icons the Levellers also regularly use the mandolin in their songs.\n", + "0.39: The Greco-Egyptian scientist Claudius Ptolemy referred to the larger island as great Britain (μεγάλης Βρεττανίας - megális Brettanias) and to Ireland as little Britain (μικρής Βρεττανίας - mikris Brettanias) in his work Almagest (147–148 AD). In his later work, Geography (c. 150 AD), he gave these islands the names Alwion, Iwernia, and Mona (the Isle of Man), suggesting these may have been names of the individual islands not known to him at the time of writing Almagest. The name Albion appears to have fallen out of use sometime after the Roman conquest of Great Britain, after which Britain became the more commonplace name for the island called Great Britain.\n", + "0.39: The Greco-Egyptian scientist Claudius Ptolemy referred to the larger island as great Britain (μεγάλης Βρεττανίας - megális Brettanias) and to Ireland as little Britain (μικρής Βρεττανίας - mikris Brettanias) in his work Almagest (147–148 AD). In his later work, Geography (c. 150 AD), he gave these islands the names Alwion, Iwernia, and Mona (the Isle of Man), suggesting these may have been names of the individual islands not known to him at the time of writing Almagest. The name Albion appears to have fallen out of use sometime after the Roman conquest of Great Britain, after which Britain became the more commonplace name for the island called Great Britain.\n", + "0.39: The Greco-Egyptian scientist Claudius Ptolemy referred to the larger island as great Britain (μεγάλης Βρεττανίας - megális Brettanias) and to Ireland as little Britain (μικρής Βρεττανίας - mikris Brettanias) in his work Almagest (147–148 AD). In his later work, Geography (c. 150 AD), he gave these islands the names Alwion, Iwernia, and Mona (the Isle of Man), suggesting these may have been names of the individual islands not known to him at the time of writing Almagest. The name Albion appears to have fallen out of use sometime after the Roman conquest of Great Britain, after which Britain became the more commonplace name for the island called Great Britain.\n", "\n", "RESPONSE: \n", - "Cillian Murphy, before achieving fame in Hollywood, performed as a troupe member with the Corcadorca Theatre Company in Cork, Ireland.\n", + "Little Britain, according to the Greco-Egyptian scientist Claudius Ptolemy, refers to Ireland. In his work Almagest, Ptolemy referred to the larger island as Great Britain and to Ireland as Little Britain.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "What kind of weather does Cork get?\n", + "What is the second smallest large urban area listed?\n", "\n", "CONTEXT:\n", - "0.2: The climate of Cork, like the rest of Ireland, is mild and changeable with abundant rainfall and a lack of temperature extremes. Cork lies in plant Hardiness zone 9b. Met Éireann maintains a climatological weather station at Cork Airport, a few kilometres south of the city. It should be noted that the airport is at an altitude of 151 metres (495 ft) and temperatures can often differ by a few degrees between the airport and the city itself. There are also smaller synoptic weather stations at UCC and Clover Hill.\n", - "0.22: Cork is also a generally foggy city, with an average of 97 days of fog a year, most common during mornings and during winter. Despite this, however, Cork is also one of Ireland's sunniest cities, with an average of 3.9 hours of sunshine every day and only having 67 days where there is no \"recordable sunshine\", mostly during and around winter.\n", - "0.25: Temperatures below 0 °C (32 °F) or above 25 °C (77 °F) are rare. Cork Airport records an average of 1,227.9 millimetres (4.029 ft) of precipitation annually, most of which is rain. The airport records an average of 7 days of hail and 11 days of snow or sleet a year; though it only records lying snow for 2 days of the year. The low altitude of the city, and moderating influences of the harbour, mean that lying snow very rarely occurs in the city itself. There are on average 204 \"rainy\" days a year (over 0.2 millimetres (0.0079 in) of rainfall), of which there are 73 days with \"heavy rain\" (over 5 millimetres (0.20 in)).\n", + "0.4: In its 2013 ParkScore ranking, The Trust for Public Land reported that the park system in New York City was the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis. ParkScore ranks urban park systems by a formula that analyzes median park size, park acres as percent of city area, the percent of city residents within a half-mile of a park, spending of park services per resident, and the number of playgrounds per 10,000 residents.\n", + "0.4: In its 2013 ParkScore ranking, The Trust for Public Land reported that the park system in New York City was the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis. ParkScore ranks urban park systems by a formula that analyzes median park size, park acres as percent of city area, the percent of city residents within a half-mile of a park, spending of park services per resident, and the number of playgrounds per 10,000 residents.\n", + "0.4: In its 2013 ParkScore ranking, The Trust for Public Land reported that the park system in New York City was the second best park system among the 50 most populous U.S. cities, behind the park system of Minneapolis. ParkScore ranks urban park systems by a formula that analyzes median park size, park acres as percent of city area, the percent of city residents within a half-mile of a park, spending of park services per resident, and the number of playgrounds per 10,000 residents.\n", "\n", "RESPONSE: \n", - "Cork experiences a mild and changeable climate with abundant rainfall and a lack of temperature extremes. The city is generally foggy, with an average of 97 days of fog per year, most common during mornings and winter. Cork is also one of Ireland's sunniest cities, with an average of 3.9 hours of sunshine per day. Temperature extremes below 0 °C (32 °F) or above 25 °C (77 °F) are rare. The city receives an\n", + "Based on the information provided, I don't have the specific details about the sizes of the urban areas listed. Without more specific information or a list of the urban areas, I cannot determine the second smallest large urban area.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "Which of the following is not a song: I Want It All, The Invisible Man, or The Miracle?\n", + "Which country is governed by a national assembly?\n", "\n", "CONTEXT:\n", - "0.33: After working on various solo projects during 1988 (including Mercury's collaboration with Montserrat Caballé, Barcelona), the band released The Miracle in 1989. The album continued the direction of A Kind of Magic, using a pop-rock sound mixed with a few heavy numbers. It spawned the European hits \"I Want It All\", \"Breakthru\", \"The Invisible Man\", \"Scandal\", and \"The Miracle\". The Miracle also began a change in direction of Queen's songwriting philosophy. Since the band's beginning, nearly all songs had been written by and credited to a single member, with other members adding minimally. With The Miracle, the band's songwriting became more collaborative, and they vowed to credit the final product only to Queen as a group.\n", - "0.45: Others found renewed success in the singles charts with power ballads, including REO Speedwagon with \"Keep on Loving You\" (1980) and \"Can't Fight This Feeling\" (1984), Journey with \"Don't Stop Believin'\" (1981) and \"Open Arms\" (1982), Foreigner's \"I Want to Know What Love Is\", Scorpions' \"Still Loving You\" (both from 1984), Heart’s \"What About Love\" (1985) and \"These Dreams\" (1986), and Boston's \"Amanda\" (1986).\n", - "0.47: Certain staples of classical music are often used commercially (either in advertising or in movie soundtracks). In television commercials, several passages have become clichéd, particularly the opening of Richard Strauss' Also sprach Zarathustra (made famous in the film 2001: A Space Odyssey) and the opening section \"O Fortuna\" of Carl Orff's Carmina Burana, often used in the horror genre; other examples include the Dies Irae from the Verdi Requiem, Edvard Grieg's In the Hall of the Mountain King from Peer Gynt, the opening bars of Beethoven's Symphony No. 5, Wagner's Ride of the Valkyries from Die Walküre, Rimsky-Korsakov's Flight of the Bumblebee, and excerpts of Aaron Copland's Rodeo.\n", + "0.37: In fact, there was an eighth province, the County of Drenthe, but this area was so poor it was exempt from paying federal taxes and as a consequence was denied representation in the States General. Each province was governed by the Provincial States, the main executive official (though not the official head of state) was a raadspensionaris. In times of war, the stadtholder, who commanded the army, would have more power than the raadspensionaris.\n", + "0.37: In fact, there was an eighth province, the County of Drenthe, but this area was so poor it was exempt from paying federal taxes and as a consequence was denied representation in the States General. Each province was governed by the Provincial States, the main executive official (though not the official head of state) was a raadspensionaris. In times of war, the stadtholder, who commanded the army, would have more power than the raadspensionaris.\n", + "0.37: In fact, there was an eighth province, the County of Drenthe, but this area was so poor it was exempt from paying federal taxes and as a consequence was denied representation in the States General. Each province was governed by the Provincial States, the main executive official (though not the official head of state) was a raadspensionaris. In times of war, the stadtholder, who commanded the army, would have more power than the raadspensionaris.\n", "\n", "RESPONSE: \n", - "Based on my knowledge, \"The Miracle\" is not a song. \"I Want It All\" and \"The Invisible Man\" are both songs by Queen.\n", + "The Netherlands is governed by a national assembly called the States General.\n", "\n", "----------------------------------------------------------------------\n", "\n", "QUERY:\n", - "What is Milton Keynes last name?\n", + "What was Ireland an exception to?\n", "\n", "CONTEXT:\n", - "0.46: Other notable Old Etonians include scientists Robert Boyle, John Maynard Smith, J. B. S. Haldane, Stephen Wolfram and the 2012 Nobel Prize in Physiology or Medicine winner, John Gurdon; Beau Brummell; economists John Maynard Keynes and Richard Layard; Antarctic explorer Lawrence Oates; politician Alan Clark; entrepreneur, charity organiser and partner of Adele, Simon Konecki; cricket commentator Henry Blofeld; explorer Sir Ranulph Fiennes; adventurer Bear Grylls; composers Thomas Arne, George Butterworth, Roger Quilter, Frederick Septimus Kelly, Donald Tovey, Thomas Dunhill, Lord Berners, Victor Hely-Hutchinson, and Peter Warlock (Philip Heseltine); Hubert Parry, who wrote the song Jerusalem and the coronation anthem I was glad; and musicians Frank Turner and Humphrey Lyttelton.\n", - "0.48: In June 1990, The Times ceased its policy of using courtesy titles (\"Mr\", \"Mrs\", or \"Miss\" prefixes) for living persons before full names on first reference, but it continues to use them before surnames on subsequent references. The more formal style is now confined to the \"Court and Social\" page, though \"Ms\" is now acceptable in that section, as well as before surnames in news sections.\n", - "0.49: In 1762, George III acquired Buckingham House and it was enlarged over the next 75 years. During the 18th century, London was dogged by crime, and the Bow Street Runners were established in 1750 as a professional police force. In total, more than 200 offences were punishable by death, including petty theft. Most children born in the city died before reaching their third birthday. The coffeehouse became a popular place to debate ideas, with growing literacy and the development of the printing press making news widely available; and Fleet Street became the centre of the British press.\n", + "0.33: Newfoundland reverted to colonial status in 1933, suffering from financial difficulties during the Great Depression. Ireland distanced itself further from Britain with the introduction of a new constitution in 1937, making it a republic in all but name.\n", + "0.33: Newfoundland reverted to colonial status in 1933, suffering from financial difficulties during the Great Depression. Ireland distanced itself further from Britain with the introduction of a new constitution in 1937, making it a republic in all but name.\n", + "0.33: Newfoundland reverted to colonial status in 1933, suffering from financial difficulties during the Great Depression. Ireland distanced itself further from Britain with the introduction of a new constitution in 1937, making it a republic in all but name.\n", "\n", "RESPONSE: \n", - "Based on my knowledge, Milton Keynes does not have a last name. However, if you are referring to the town of Milton Keynes in Buckinghamshire, England, it is named after the existing villages of Milton Keynes, Bletchley, and Wolverton.\n", + "Ireland was an exception to the British rule, as it distanced itself further from Britain with the introduction of a new constitution in 1937, making it a republic in all but name.\n", "\n", "----------------------------------------------------------------------\n" ] @@ -567,7 +567,7 @@ " ]\n", " \n", " # send the messages to a GPT model\n", - " response = openai.ChatCompletion.create(\n", + " response = openai.chat.completions.create(\n", " model=\"gpt-3.5-turbo\",\n", " messages=messages,\n", " max_tokens=100,\n", @@ -576,7 +576,7 @@ " )\n", "\n", " # extract the generated response from the API response\n", - " generated_response =response['choices'][0]['message']['content']\n", + " generated_response = response.choices[0].message.content\n", " \n", " # Print the generated response\n", " print(f\"RESPONSE: \\n{generated_response}\\n\")\n", @@ -599,7 +599,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ From a75801d82efd901afeafe151aff20f026c54a13a Mon Sep 17 00:00:00 2001 From: Bruno LE HYARIC Date: Thu, 9 Nov 2023 18:40:15 +0100 Subject: [PATCH 26/28] Amend README and add setup documentation for KDB.AI vector database. --- README.md | 8 ++++++++ docs/providers/kdbai/setup.md | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 docs/providers/kdbai/setup.md diff --git a/README.md b/README.md index 56653b064..5dad7e9ff 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,10 @@ Follow these steps to quickly set up and run the ChatGPT Retrieval Plugin: export MILVUS_USER= export MILVUS_PASSWORD= + # KDB.AI + export KDBAI_ENDPOINT= + export KDBAI_API_KEY= + # Qdrant export QDRANT_URL= export QDRANT_PORT= @@ -325,6 +329,10 @@ For more detailed instructions on setting up and using each vector database prov [Milvus](https://milvus.io/) is an open-source, cloud-native vector database that scales to billions of vectors. It is the open-source version of Zilliz and shares many of its features, such as various indexing algorithms, distance metrics, scalar filtering, time travel searches, rollback with snapshots, multi-language SDKs, storage and compute separation, and cloud scalability. For detailed setup instructions, refer to [`/docs/providers/milvus/setup.md`](/docs/providers/milvus/setup.md). +#### KDB.AI + +[KDB.AI](https://kdb.ai) is a powerful knowledge-based vector database and search engine that allows developers to build scalable, reliable and real-time applications by providing advanced search, recommendation and personalization for AI applications, using real-time data. For detailed setup instructions, refer to [`/docs/providers/kdbai/setup.md`](/docs/providers/kdbai/setup.md). + #### Qdrant [Qdrant](https://qdrant.tech/) is a vector database capable of storing documents and vector embeddings. It offers both self-hosted and managed [Qdrant Cloud](https://cloud.qdrant.io/) deployment options, providing flexibility for users with different requirements. For detailed setup instructions, refer to [`/docs/providers/qdrant/setup.md`](/docs/providers/qdrant/setup.md). diff --git a/docs/providers/kdbai/setup.md b/docs/providers/kdbai/setup.md new file mode 100644 index 000000000..36197432f --- /dev/null +++ b/docs/providers/kdbai/setup.md @@ -0,0 +1,16 @@ +# KDB.AI + +[KDB.AI](https://kdb.ai) is a powerful knowledge-based vector database and search engine that allows developers to build scalable, reliable and real-time applications by providing advanced search, recommendation and personalization for AI applications, using real-time data. You can register for Free Trial on https://kdb.ai. + +You can find a sample notebook to use the ChatGPT Retrieval Plugin backed by KDB.AI vector database [here](https://github.com/KxSystems/chatgpt-retrieval-plugin/blob/KDB.AI/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb) and instructions to get started [here](https://code.kx.com/kdbai/integrations/openai.html). + +**Environment Variables:** + +| Name | Required | Description | Default | +| ------------------- | -------- | ----------------------------------------------------------- | ------------------ | +| `DATASTORE` | Yes | Datastore name, set to `kdbai` | | +| `BEARER_TOKEN` | Yes | Secret token | | +| `OPENAI_API_KEY` | Yes | OpenAI API key | | +| `KDBAI_ENDPOINT` | Yes | KDB.AI endpoint | | +| `KDBAI_API_KEY` | Yes | KDB.AI API key | | +| `KDBAI_TABLE` | Optional | TCP port for Qdrant GRPC communication | `documents` | From 83462f5918025078f969fcf3def4aaacbfe6c0d9 Mon Sep 17 00:00:00 2001 From: agiannakoulopoulos Date: Tue, 9 Apr 2024 03:39:51 +0300 Subject: [PATCH 27/28] Update kdbai_datastore.py --- datastore/providers/kdbai_datastore.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/datastore/providers/kdbai_datastore.py b/datastore/providers/kdbai_datastore.py index e8f3910fe..a22c38550 100644 --- a/datastore/providers/kdbai_datastore.py +++ b/datastore/providers/kdbai_datastore.py @@ -42,7 +42,7 @@ if KDBAI_API_KEY == '': KDBAI_API_KEY = None -DEFAULT_DIMS = 1536 +DEFAULT_DIMS = 3072 BATCH_SIZE = 100 DEFAULT_SCHEMA = dict( @@ -133,7 +133,7 @@ async def _query( raise e docs = [] - for result in resdf.to_dict(orient='record'): + for result in resdf.to_dict(orient='records'): docs.append(DocumentChunkWithScore( id=result['document_id'], text=result['text'], @@ -153,14 +153,14 @@ async def delete( ) -> bool: """ - Removes vectors by ids, filter, or everything from the index. + Delete all vectors and assosiated index. """ # Delete all vectors and assosiated index try: if delete_all: self._table.drop() - logger.info(f"Deleted all vectors successfully") + logger.info(f"Deleted all vectors and index successfully") return True else: logger.error("Functionality is not implemented yet") From c3e498a269148849938e325c57f75bfe5ac554ed Mon Sep 17 00:00:00 2001 From: agiannakoulopoulos Date: Tue, 9 Apr 2024 03:44:38 +0300 Subject: [PATCH 28/28] Update kdb.AI example notebook --- examples/providers/kdbai/ChatGPT_QA_Demo.ipynb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb index 813c5960d..129d4c0d6 100644 --- a/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb +++ b/examples/providers/kdbai/ChatGPT_QA_Demo.ipynb @@ -266,7 +266,7 @@ } ], "source": [ - "data = load_dataset(\"adversarial_qa\", 'adversarialQA', split=\"train\").to_pandas()\n", + "data = load_dataset(\"adversarial_qa\", 'adversarialQA', ignore_verifications=True)['train'].to_pandas()\n", "data = data.drop_duplicates(subset=[\"context\"])\n", "print(f\"Number of unique contexts: {len(data)}\")\n", "data.head()" @@ -308,7 +308,11 @@ "# extract text data from the dataset\n", "documents = [\n", " {\n", + " 'id': r['id'],\n", " 'text': r['context'],\n", + " 'metadata': {\n", + " 'title': r['title']\n", + " }\n", " } for r in data.to_dict(orient='records')\n", "]\n", "pprint(documents[0])"