From bafb475c7e6a9ca2586a62b35c8e4d6adaf2b570 Mon Sep 17 00:00:00 2001 From: ragul-kachiappan Date: Tue, 27 Feb 2024 16:13:12 +0530 Subject: [PATCH 01/79] fix: default collection embedding function attribute in ChromadbRM constructor --- dspy/retrieve/chromadb_rm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspy/retrieve/chromadb_rm.py b/dspy/retrieve/chromadb_rm.py index 1338d48d5..b55fec8ff 100644 --- a/dspy/retrieve/chromadb_rm.py +++ b/dspy/retrieve/chromadb_rm.py @@ -74,7 +74,7 @@ def __init__( k: int = 7, ): self._init_chromadb(collection_name, persist_directory) - self.ef = embedding_function or self._chromadb_collection.embedding_function + self.ef = embedding_function or self._chromadb_collection._embedding_function super().__init__(k=k) From 7e7ed09215896acc5fb45fab7d7eadd2be527dae Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Tue, 27 Feb 2024 20:15:52 -0800 Subject: [PATCH 02/79] adding in bayesian optimizer notebook, plus a few minor changes to bayesian optimizer --- dspy/teleprompt/signature_opt_bayesian.py | 66 +- examples/qa/hotpot/hotpotqa_optimized.ipynb | 1915 +++++++++++++++++++ 2 files changed, 1953 insertions(+), 28 deletions(-) create mode 100644 examples/qa/hotpot/hotpotqa_optimized.ipynb diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index 68d7aacf0..bca0d299d 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -65,12 +65,12 @@ class BasicGenerateInstructionWithExamples(dspy.Signature): proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") class BasicGenerateInstructionWithExamplesAndDataObservations(dspy.Signature): - ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``observations`` I have made about the dataset and task, along with some ``examples`` of the expected inputs and outputs. + ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will give you some ``observations`` I have made about the dataset and task, along with some ``examples`` of the expected inputs and outputs. I will also provide you with the current ``basic instruction`` that is being used for this task. Your task is to propose a new improved instruction and prefix for the output field that will lead a good language model to perform the task well. Don't be afraid to be creative.""") - basic_instruction = dspy.InputField(desc="The initial instructions before optimization") observations = dspy.InputField(desc="Observations about the dataset and task") examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") + basic_instruction = dspy.InputField(desc="The initial instructions before optimization") proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") @@ -112,12 +112,8 @@ def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10 def _print_full_program(self, program): for i,predictor in enumerate(program.predictors()): if self.verbose: print(f"Predictor {i}") - if (hasattr(predictor, 'extended_signature')): - if self.verbose: print(f"i: {predictor.extended_signature.instructions}") - if self.verbose: print(f"p: {predictor.extended_signature.fields[-1].name}") - else: - if self.verbose: print(f"i: {predictor.extended_signature1.instructions}") - if self.verbose: print(f"p: {predictor.extended_signature1.fields[-1].name}") + if self.verbose: print(f"i: {self._get_signature(predictor).instructions}") + if self.verbose: print(f"p: {self._get_signature(predictor).fields[-1].name}") if self.verbose: print("\n") def _print_model_history(self, model, n=1): @@ -162,6 +158,12 @@ def _create_example_string(self, fields, example): # Joining all the field strings return '\n'.join(output) + + def _get_signature(self, predictor): + if (hasattr(predictor, 'extended_signature')): + return predictor.extended_signature + elif (hasattr(predictor, 'signature')): + return predictor.signature def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo_candidates, devset): candidates = {} @@ -186,7 +188,7 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo if example["augmented"]: if example_set_i not in example_set: example_set[example_set_i] = [] - fields_to_use = predictor.signature.fields + fields_to_use = self._get_signature(predictor).fields input_variable_names = [field.input_variable for field in fields_to_use] example_with_only_signature_fields = {key: value for key, value in example.items() if key in input_variable_names} example_string = self._create_example_string(fields_to_use, example_with_only_signature_fields) @@ -200,12 +202,8 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo for predictor in module.predictors(): basic_instruction = None basic_prefix = None - if (hasattr(predictor, 'extended_signature')): - basic_instruction = predictor.extended_signature.instructions - basic_prefix = predictor.extended_signature.fields[-1].name - else: - basic_instruction = predictor.extended_signature1.instructions - basic_prefix = predictor.extended_signature1.fields[-1].name + basic_instruction = self._get_signature(predictor).instructions + basic_prefix = self._get_signature(predictor).fields[-1].name with dspy.settings.context(lm=self.prompt_model): # Data & Examples if view_data and view_examples: @@ -251,6 +249,14 @@ def compile(self, student, *, devset, optuna_trials_num, max_bootstrapped_demos, # Set up program and evaluation function module = student.deepcopy() evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) + + # In the case where the bootstrapped and labeled demos are set to 0, we'll stil bootstrap examples to use in our meta prompt + if max_bootstrapped_demos==0 and max_labeled_demos==0: #TODO: address case when max_bootstrapped alone is 0 + max_bootstrapped_demos_for_candidate_gen = 1 + max_labeled_demos_for_candidate_gen = 1 #TODO: this might only need to be 0 + else: + max_bootstrapped_demos_for_candidate_gen = max_bootstrapped_demos + max_labeled_demos_for_candidate_gen = max_labeled_demos # Generate N few shot example sets demo_candidates = {} @@ -267,7 +273,7 @@ def compile(self, student, *, devset, optuna_trials_num, max_bootstrapped_demos, rng = random.Random(i) shuffled_devset = devset[:] # Create a copy of devset rng.shuffle(shuffled_devset) # Shuffle the copy - tp = BootstrapFewShot(metric = self.metric, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, teacher_settings=self.teacher_settings) + tp = BootstrapFewShot(metric = self.metric, max_bootstrapped_demos=max_bootstrapped_demos_for_candidate_gen, max_labeled_demos=max_labeled_demos_for_candidate_gen, teacher_settings=self.teacher_settings) candidate_program = tp.compile(student=module.deepcopy(), trainset=shuffled_devset) # Store the candidate demos @@ -275,10 +281,14 @@ def compile(self, student, *, devset, optuna_trials_num, max_bootstrapped_demos, if id(module_p) not in demo_candidates.keys(): demo_candidates[id(module_p)] = [] demo_candidates[id(module_p)].append(candidate_p.demos) - + # Generate N candidate prompts instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, devset) + # Reset demo_candidates to None for our optimization if the user asked for no fewshot examples + if max_bootstrapped_demos==0 and max_labeled_demos==0: + demo_candidates = None + # Initialize variables to store the best program and its score best_score = float('-inf') best_program = None @@ -293,20 +303,20 @@ def objective(trial): candidate_program = baseline_program.deepcopy() # Suggest the instruction to use for our predictor - if self.verbose: print(f"Starting trial num: {trial_num}") + print(f"Starting trial #{trial_num}") trial_logs[trial_num] = {} for p_old, p_new in zip(baseline_program.predictors(), candidate_program.predictors()): # Get instruction candidates for our given predictor p_instruction_candidates = instruction_candidates[id(p_old)] - p_demo_candidates = demo_candidates[id(p_old)] + if demo_candidates: p_demo_candidates = demo_candidates[id(p_old)] # Suggest the index of the instruction candidate to use in our trial instruction_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_instruction",range(len(p_instruction_candidates))) - demos_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_demos",range(len(p_demo_candidates))) + if demo_candidates: demos_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_demos",range(len(p_demo_candidates))) trial_logs[trial_num][f"{id(p_old)}_predictor_instruction"] = instruction_idx - trial_logs[trial_num][f"{id(p_old)}_predictor_demos"] = demos_idx + if demo_candidates: trial_logs[trial_num][f"{id(p_old)}_predictor_demos"] = demos_idx # Get the selected instruction candidate selected_candidate = p_instruction_candidates[instruction_idx] @@ -314,17 +324,17 @@ def objective(trial): selected_prefix = selected_candidate.proposed_prefix_for_output_field.strip('"').strip() # Use this candidates in our program - p_new.extended_signature.instructions = selected_instruction - p_new.extended_signature.fields[-1] = p_new.extended_signature.fields[-1]._replace(name=selected_prefix) + self._get_signature(p_new).instructions = selected_instruction + self._get_signature(p_new).fields[-1] = self._get_signature(p_new).fields[-1]._replace(name=selected_prefix) # Get the selected demos - selected_demos = p_demo_candidates[demos_idx] + if demo_candidates: selected_demos = p_demo_candidates[demos_idx] # Use these demos in our program - p_new.demos = selected_demos + if demo_candidates: p_new.demos = selected_demos if self.verbose: print("Evaling the following program:") - self._print_full_program(candidate_program) + if self.verbose: self._print_full_program(candidate_program) trial_logs[trial_num]["program"] = candidate_program # Evaluate with the new prompts @@ -347,14 +357,14 @@ def objective(trial): # Handle pruning based on the intermediate value. if trial.should_prune(): - if self.verbose: print(f"Optuna decided to prune!") + print(f"Trial pruned.") trial_logs[trial_num]["score"] = curr_weighted_avg_score trial_logs[trial_num]["pruned"] = True trial_num += 1 raise optuna.TrialPruned() if self.verbose: print(f"Fully evaled score: {curr_weighted_avg_score}") - self._print_model_history(self.task_model, n=1) + if self.verbose: self._print_model_history(self.task_model, n=1) score = curr_weighted_avg_score trial_logs[trial_num]["score"] = curr_weighted_avg_score diff --git a/examples/qa/hotpot/hotpotqa_optimized.ipynb b/examples/qa/hotpot/hotpotqa_optimized.ipynb new file mode 100644 index 000000000..cf002054e --- /dev/null +++ b/examples/qa/hotpot/hotpotqa_optimized.ipynb @@ -0,0 +1,1915 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# __DSPy Prompt Optimizers__: Optimizing instructions & fewshot examples for LM programs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Description of this notebook, what you'll learn, etc." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 0] Setup" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we'll __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "unterminated string literal (detected at line 11) (1838760429.py, line 11)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn[1], line 11\u001b[0;36m\u001b[0m\n\u001b[0;31m os.environ[\"DSP_CACHEDIR\"] = f\"repo_clone_path/sub_dir\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m unterminated string literal (detected at line 11)\n" + ] + } + ], + "source": [ + "!rm -rf DSPy_optimizer_cache\n", + "!git clone https://huggingface.co/kopsahlong/DSPy_optimizer_cache\n", + "%cd DSPy_optimizer_cache/\n", + "# !git checkout master\n", + "%cd ..\n", + "import os\n", + "repo_clone_path = 'DSPy_optimizer_cache/cache' #TODO: update this cache to just contain the runs we need!!\n", + "\n", + "# Set up the cache for this notebook\n", + "os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = repo_clone_path\n", + "os.environ[\"DSP_CACHEDIR\"] = f\"{repo_clone_path}/cachedir\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/lfs/0/kristaoo/home\n" + ] + } + ], + "source": [ + "!echo $HOME" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will also specify the __prompt LM model__ (in this case GPT 3.5), the __task LM model__ (Llama 13B) and the retrieval model we'll be using for our task (a HotPotQA multihop retrieval task)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/lfs/0/kristaoo/miniconda3/envs/dspy_test/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 dspy\n", + "import openai\n", + "import os\n", + "\n", + "### NOTE: if you'd like to run this code without a cache, you can remove these lines to configure your OPEN AI key ###\n", + "# os.environ['OPENAI_API_KEY'] = \"TODO: ADD YOUR OPEN AI KEY HERE\"\n", + "# openai.api_key = os.environ.get('OPENAI_API_KEY')\n", + "# openai.api_base = \"https://api.openai.com/v1\"\n", + "\n", + "prompt_model_name = \"gpt-3.5-turbo-1106\"\n", + "task_model_name = \"meta-llama/Llama-2-13b-chat-hf\"\n", + "colbert_v2_endpoint = \"http://20.102.90.50:2017/wiki17_abstracts\"\n", + "\n", + "ports = [7140, 7141, 7142, 7143] #TODO: REMOVE THIS\n", + "\n", + "prompt_model = dspy.OpenAI(model=prompt_model_name, max_tokens=150)\n", + "task_model = dspy.HFClientTGI(model=task_model_name, port=[7140, 7141, 7142, 7143], max_tokens=150)\n", + "\n", + "colbertv2 = dspy.ColBERTv2(url=colbert_v2_endpoint)\n", + "\n", + "dspy.settings.configure(rm=colbertv2, lm=task_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1] Define Task" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we'll define the program that we'd like to run, which is a multihop [...] (we can say that it was loosely inspired by a certain paper). We additionally load in the data, and define how we'd like to evaluate this task." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/lfs/0/kristaoo/miniconda3/envs/dspy_test/lib/python3.10/site-packages/datasets/table.py:1421: FutureWarning: promote has been superseded by mode='default'.\n", + " table = cls._concat_blocks(blocks, axis=0)\n" + ] + } + ], + "source": [ + "from dspy.evaluate import Evaluate\n", + "import re \n", + "from dspy.datasets import HotPotQA\n", + "\n", + "class ReturnRankedDocuments(dspy.Signature):\n", + " \"\"\"Given a question we are trying to answer and a list of passages, return a comma separated list of the numbers associated with each passage. These numbers should be ordered by helpfulness in answering the question, with most helpful passage number first, and the least helpful last.\"\"\"\n", + " question = dspy.InputField(desc=\"The question we're trying to answer.\")\n", + " context = dspy.InputField(desc=\"List of potentially related passages.\")\n", + " ranking = dspy.OutputField(desc=\"A comma separated list of numbers corresponding to passage indices, ranked in descending order by their helpfulness in answering our question.\")\n", + "\n", + "class RankingMultiHop(dspy.Module):\n", + " def __init__(self, hops, num_passages_to_retrieve, max_passages_in_context):\n", + " super().__init__()\n", + " self.hops = hops\n", + " self.num_passages_to_retrieve = num_passages_to_retrieve\n", + " self.max_passages_in_context = max_passages_in_context\n", + " self.retrieve = dspy.Retrieve(k = self.num_passages_to_retrieve)\n", + " self.generate_query = dspy.ChainOfThought(\"context ,question->search_query\")\n", + " self.generate_answer = dspy.ChainOfThought(\"context ,question->answer\")\n", + " self.generate_ranking = dspy.ChainOfThought(ReturnRankedDocuments)\n", + " \n", + " def forward (self,question) :\n", + " context = []\n", + " full_context = []\n", + " top_context = []\n", + " max_passage_num = self.max_passages_in_context\n", + " for hop in range(self.hops):\n", + " # Get a new query\n", + " query = self.generate_query(context = context, question = question).search_query\n", + " # Get new passages\n", + " context = self.retrieve(query).passages\n", + " # Add these new passages to the previous top context \n", + " full_context = top_context + context\n", + " # Get the most important indices, ranked\n", + " most_important_indices = self.generate_ranking(question=question, context=full_context).ranking\n", + " indices = [int(num) for num in re.findall(r'\\d+', most_important_indices)]\n", + "\n", + " if len(indices) < max_passage_num:\n", + " indices = range(1,max_passage_num+1)\n", + "\n", + " valid_indices = [index-1 for index in indices if index-1 < len(context)]\n", + " top_indices = sorted(valid_indices, key=lambda x: x)[:max_passage_num+1]\n", + " most_important_context_list = [context[idx] for idx in top_indices]\n", + " # Save the top context\n", + " top_context = most_important_context_list\n", + "\n", + " return dspy.Prediction(context=context, answer=self.generate_answer(context = top_context , question = question).answer)\n", + "\n", + "program = RankingMultiHop(hops=4, num_passages_to_retrieve=5, max_passages_in_context=5)\n", + "\n", + "# Load and configure the datasets.\n", + "TRAIN_SIZE = 500\n", + "EVAL_SIZE = 500\n", + "\n", + "hotpot_dataset = HotPotQA(train_seed=1, eval_seed=2023, test_size=0)\n", + "trainset = [x.with_inputs('question') for x in hotpot_dataset.train][:TRAIN_SIZE]\n", + "devset = [x.with_inputs('question') for x in hotpot_dataset.dev][:EVAL_SIZE]\n", + "\n", + "# Set up metrics\n", + "NUM_THREADS = 10\n", + "\n", + "metric = dspy.evaluate.answer_exact_match\n", + "\n", + "# kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=None)\n", + "kwargs = dict(num_threads=NUM_THREADS, display_progress=True)\n", + "evaluate = Evaluate(devset=devset, metric=metric, **kwargs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2] Baseline Evaluation\n", + "Now, we'll quickly evaluate our baseline program so that we can see how the performance using the Prompt Optimizer compares. We should see performance of about __16%__ on our trainset, and __21.4%__ on our devset." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " 0%| | 0/500 [00:00 Date: Thu, 29 Feb 2024 14:15:28 +0530 Subject: [PATCH 03/79] fix: use generic embedding function as default in ChromadbRM --- dspy/retrieve/chromadb_rm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspy/retrieve/chromadb_rm.py b/dspy/retrieve/chromadb_rm.py index b55fec8ff..e41be8427 100644 --- a/dspy/retrieve/chromadb_rm.py +++ b/dspy/retrieve/chromadb_rm.py @@ -70,11 +70,11 @@ def __init__( persist_directory: str, embedding_function: Optional[ EmbeddingFunction[Embeddable] - ] = None, + ] = ef.DefaultEmbeddingFunction(), k: int = 7, ): self._init_chromadb(collection_name, persist_directory) - self.ef = embedding_function or self._chromadb_collection._embedding_function + self.ef = embedding_function super().__init__(k=k) From cbed0b9cb96c6f8696fc461f8a12e6057dec2f52 Mon Sep 17 00:00:00 2001 From: Omar Khattab Date: Sat, 2 Mar 2024 23:17:45 +0000 Subject: [PATCH 04/79] OpenAI: No retry on ServiceUnavailableError, APIError --- dsp/modules/gpt3.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dsp/modules/gpt3.py b/dsp/modules/gpt3.py index e19ca40f5..be1d1e7f4 100644 --- a/dsp/modules/gpt3.py +++ b/dsp/modules/gpt3.py @@ -30,11 +30,9 @@ ERRORS = ( openai.error.RateLimitError, - openai.error.ServiceUnavailableError, - openai.error.APIError, ) except Exception: - ERRORS = (openai.RateLimitError, openai.APIError) + ERRORS = (openai.RateLimitError,) OpenAIObject = dict From c81e973f6decb127c87501fa54d1e9b1d3265a83 Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Mon, 4 Mar 2024 20:15:08 +0100 Subject: [PATCH 05/79] Add support for neo4j vector index --- dspy/retrieve/neo4j_rm.py | 104 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 dspy/retrieve/neo4j_rm.py diff --git a/dspy/retrieve/neo4j_rm.py b/dspy/retrieve/neo4j_rm.py new file mode 100644 index 000000000..20a5b7b33 --- /dev/null +++ b/dspy/retrieve/neo4j_rm.py @@ -0,0 +1,104 @@ +import os +from typing import Any, List, Optional, Union + +import backoff +from openai import ( + APITimeoutError, + InternalServerError, + OpenAI, + RateLimitError, + UnprocessableEntityError, +) + +import dspy +from dsp.utils import dotdict + +try: + from neo4j import GraphDatabase + from neo4j.exceptions import ( + AuthError, + ServiceUnavailable, + ) +except ImportError: + raise ImportError( + "Please install the neo4j package by running `pip install dspy-ai[neo4j]`", + ) + + +class Embedder: + def __init__(self, provider: str, model: str): + if provider == "openai": + api_key = os.getenv("OPENAI_API_KEY") + if not api_key: + raise ValueError("Environment variable OPENAI_API_KEY must be set") + self.client = OpenAI() + self.model = model + + @backoff.on_exception( + backoff.expo, + ( + APITimeoutError, + InternalServerError, + RateLimitError, + UnprocessableEntityError, + ), + max_time=15, + ) + def __call__(self, queries) -> Any: + embedding = self.client.embeddings.create(input=queries, model=self.model) + return [result.embedding for result in embedding.data] + + +DEFAULT_INDEX_QUERY = "CALL db.index.vector.queryNodes($index, $k, $embedding) YIELD node, score " + + +class Neo4jRM(dspy.Retrieve): + def __init__( + self, + index_name: str, + text_node_property: str, + k: int = 5, + retrieval_query: str = None, + embedding_provider: str = "openai", + embedding_model: str = "text-embedding-ada-002", + ): + super().__init__(k=k) + self.index_name = index_name + self.username = os.getenv("NEO4J_USERNAME") + self.password = os.getenv("NEO4J_PASSWORD") + self.uri = os.getenv("NEO4J_URI") + self.database = os.getenv("NEO4J_DATABASE") + self.k = k + self.retrieval_query = retrieval_query + self.text_node_property = text_node_property + if not self.username: + raise ValueError("Environment variable NEO4J_USERNAME must be set") + if not self.password: + raise ValueError("Environment variable NEO4J_PASSWORD must be set") + if not self.uri: + raise ValueError("Environment variable NEO4J_URI must be set") + try: + self.driver = GraphDatabase.driver(self.uri, auth=(self.username, self.password)) + self.driver.verify_connectivity() + + except ( + ServiceUnavailable, + AuthError, + ) as e: + raise ConnectionError("Failed to connect to Neo4j database") from e + + self.embedder = Embedder(provider=embedding_provider, model=embedding_model) + + def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> dspy.Prediction: + if not isinstance(query_or_queries, list): + query_or_queries = [query_or_queries] + query_vectors = self.embedder(query_or_queries) + contents = [] + retrieval_query = self.retrieval_query or f"RETURN node.{self.text_node_property} AS output" + for vector in query_vectors: + records, _, _ = self.driver.execute_query( + DEFAULT_INDEX_QUERY + retrieval_query, + {"embedding": vector, "index": self.index_name, "k": k or self.k}, + ) + contents.extend([dotdict({"long_text": r["output"]}) for r in records]) + return contents From c33197585cb88c44c5ee88c49a13a0d27b6bd8ab Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Mon, 4 Mar 2024 20:23:31 +0100 Subject: [PATCH 06/79] switch to text --- dspy/retrieve/neo4j_rm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspy/retrieve/neo4j_rm.py b/dspy/retrieve/neo4j_rm.py index 20a5b7b33..2c5998c49 100644 --- a/dspy/retrieve/neo4j_rm.py +++ b/dspy/retrieve/neo4j_rm.py @@ -94,11 +94,11 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> query_or_queries = [query_or_queries] query_vectors = self.embedder(query_or_queries) contents = [] - retrieval_query = self.retrieval_query or f"RETURN node.{self.text_node_property} AS output" + retrieval_query = self.retrieval_query or f"RETURN node.{self.text_node_property} AS text" for vector in query_vectors: records, _, _ = self.driver.execute_query( DEFAULT_INDEX_QUERY + retrieval_query, {"embedding": vector, "index": self.index_name, "k": k or self.k}, ) - contents.extend([dotdict({"long_text": r["output"]}) for r in records]) + contents.extend([dotdict({"long_text": r["text"]}) for r in records]) return contents From 1754cbd37d84daa6b87429d8d5fa413c5f396c43 Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Mon, 4 Mar 2024 20:38:42 +0100 Subject: [PATCH 07/79] Add docs & some improvements --- docs/api/retrieval_model_clients/Neo4jRM.md | 80 +++++++++++++++++++++ dspy/retrieve/neo4j_rm.py | 7 +- 2 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 docs/api/retrieval_model_clients/Neo4jRM.md diff --git a/docs/api/retrieval_model_clients/Neo4jRM.md b/docs/api/retrieval_model_clients/Neo4jRM.md new file mode 100644 index 000000000..dc4530f09 --- /dev/null +++ b/docs/api/retrieval_model_clients/Neo4jRM.md @@ -0,0 +1,80 @@ + +# retrieve.neo4j_rm + +### Constructor + +Initialize an instance of the `Neo4jRM` class. + +```python +Neo4jRM( + index_name: str, + text_node_property: str, + k: int = 5, + retrieval_query: str = None, + embedding_provider: str = "openai", + embedding_model: str = "text-embedding-ada-002", +) +``` + +**Environment Variables:** + +You need to define the credentials as environment variables: + +- `NEO4J_USERNAME` (_str_): Specifies the username required for authenticating with the Neo4j database. This is a crucial security measure to ensure that only authorized users can access the database. + +- `NEO4J_PASSWORD` (_str_): Defines the password associated with the `NEO4J_USERNAME` for authentication purposes. This password should be kept secure to prevent unauthorized access to the database. + +- `NEO4J_URI` (_str_): Indicates the Uniform Resource Identifier (URI) used to connect to the Neo4j database. This URI typically includes the protocol, hostname, and port, providing the necessary information to establish a connection to the database. + +- `NEO4J_DATABASE` (_str_, optional): Specifies the name of the database to connect to within the Neo4j instance. If not set, the system defaults to using `"neo4j"` as the database name. This allows for flexibility in connecting to different databases within a single Neo4j server. + +**Parameters:** +- `index_name` (_str_): Specifies the name of the vector index to be used within Neo4j for organizing and querying data. +- `text_node_property` (_str_, _optional_): Defines the specific property of nodes that will be returned. +- `k` (_int_, _optional_): The number of top results to return from the retrieval operation. It defaults to 5 if not explicitly specified. +- `retrieval_query` (_str_, _optional_): A custom query string provided for retrieving data. If not provided, a default query tailored to the `text_node_property` will be used. +- `embedding_provider` (_str_, _optional_): The name of the service provider for generating embeddings. Defaults to "openai" if not specified. +- `embedding_model` (_str_, _optional_): The specific embedding model to use from the provider. By default, it uses the "text-embedding-ada-002" model from OpenAI. + + +### Methods + +#### `forward(self, query: [str], k: Optional[int] = None) -> dspy.Prediction` + +Search the neo4j vector index for the top `k` passages matching the given query or queries, using embeddings generated via the specified `embedding_model`. + +**Parameters:** +- `query` (str_): The query. +- `k` (_Optional[int]_, _optional_): The number of results to retrieve. If not specified, defaults to the value set during initialization. + +**Returns:** +- `dspy.Prediction`: Contains the retrieved passages as a list of string with the prediction signature. + +ex: +```python +Prediction( + passages=['Passage 1 Lorem Ipsum awesome', 'Passage 2 Lorem Ipsum Youppidoo', 'Passage 3 Lorem Ipsum Yassssss'] +) +``` + +### Quick Example how to use Neo4j in a local environment. + + +```python +from dspy.retrieve.neo4j_rm import Neo4jRM +import os + +os.environ["NEO4J_URI"] = 'bolt://localhost:7687' +os.environ["NEO4J_USERNAME"] = 'neo4j' +os.environ["NEO4J_PASSWORD"] = 'password' + +retriever_model = Neo4jRM( + index_name="vector", + text_node_property="text" +) + +results = retriever_model("Explore the significance of quantum computing", k=3) + +for passage in results.passages: + print("Document:", result, "\n") +``` diff --git a/dspy/retrieve/neo4j_rm.py b/dspy/retrieve/neo4j_rm.py index 2c5998c49..db0c671ad 100644 --- a/dspy/retrieve/neo4j_rm.py +++ b/dspy/retrieve/neo4j_rm.py @@ -56,7 +56,7 @@ class Neo4jRM(dspy.Retrieve): def __init__( self, index_name: str, - text_node_property: str, + text_node_property: str = None, k: int = 5, retrieval_query: str = None, embedding_provider: str = "openai", @@ -67,7 +67,7 @@ def __init__( self.username = os.getenv("NEO4J_USERNAME") self.password = os.getenv("NEO4J_PASSWORD") self.uri = os.getenv("NEO4J_URI") - self.database = os.getenv("NEO4J_DATABASE") + self.database = os.getenv("NEO4J_DATABASE", "neo4j") self.k = k self.retrieval_query = retrieval_query self.text_node_property = text_node_property @@ -77,6 +77,8 @@ def __init__( raise ValueError("Environment variable NEO4J_PASSWORD must be set") if not self.uri: raise ValueError("Environment variable NEO4J_URI must be set") + if not self.text_node_property and not self.retrieval_query: + raise ValueError("Either `text_node_property` or `retrieval_query` parameters must be defined") try: self.driver = GraphDatabase.driver(self.uri, auth=(self.username, self.password)) self.driver.verify_connectivity() @@ -99,6 +101,7 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> records, _, _ = self.driver.execute_query( DEFAULT_INDEX_QUERY + retrieval_query, {"embedding": vector, "index": self.index_name, "k": k or self.k}, + database_=self.database, ) contents.extend([dotdict({"long_text": r["text"]}) for r in records]) return contents From ff26c02e051681238f142fa602347755769266dc Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Mon, 4 Mar 2024 22:12:47 +0100 Subject: [PATCH 08/79] Fixes --- docs/api/retrieval_model_clients/Neo4jRM.md | 3 ++ dspy/retrieve/neo4j_rm.py | 57 +++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/docs/api/retrieval_model_clients/Neo4jRM.md b/docs/api/retrieval_model_clients/Neo4jRM.md index dc4530f09..2bb2ddd2f 100644 --- a/docs/api/retrieval_model_clients/Neo4jRM.md +++ b/docs/api/retrieval_model_clients/Neo4jRM.md @@ -28,6 +28,8 @@ You need to define the credentials as environment variables: - `NEO4J_DATABASE` (_str_, optional): Specifies the name of the database to connect to within the Neo4j instance. If not set, the system defaults to using `"neo4j"` as the database name. This allows for flexibility in connecting to different databases within a single Neo4j server. +- `OPENAI_API_KEY` (_str_): Specifies the API key required for authenticiating with OpenAI's services. + **Parameters:** - `index_name` (_str_): Specifies the name of the vector index to be used within Neo4j for organizing and querying data. - `text_node_property` (_str_, _optional_): Defines the specific property of nodes that will be returned. @@ -67,6 +69,7 @@ import os os.environ["NEO4J_URI"] = 'bolt://localhost:7687' os.environ["NEO4J_USERNAME"] = 'neo4j' os.environ["NEO4J_PASSWORD"] = 'password' +os.environ["OPENAI_API_KEY"] = 'sk-' retriever_model = Neo4jRM( index_name="vector", diff --git a/dspy/retrieve/neo4j_rm.py b/dspy/retrieve/neo4j_rm.py index db0c671ad..bb5ad2523 100644 --- a/dspy/retrieve/neo4j_rm.py +++ b/dspy/retrieve/neo4j_rm.py @@ -53,6 +53,52 @@ def __call__(self, queries) -> Any: class Neo4jRM(dspy.Retrieve): + """ + Implements a retriever that utilizes Neo4j for retrieving passages. + This class manages a connection to a Neo4j database using official Neo4j Python drivers and requires + the database credentials (username, password, URI, and optionally the database name) to be set as environment variables. + Additionally, it utilizes an embedding provider (defaulting to OpenAI's services) to compute query embeddings, + which are then used to find the most relevant nodes in the Neo4j graph based on the specified node property or custom retrieval query. + + Returns a list of passages in the form of `dspy.Prediction` objects. + + Args: + index_name (str): The name of the vector index in the Neo4j database to query against. + text_node_property (Optional[str]): The property of the node containing the text. Required if `retrieval_query` is not set. + k (Optional[int]): The default number of top passages to retrieve. Defaults to 5. + retrieval_query (Optional[str]): Custom Cypher query for retrieving passages. Required if `text_node_property` is not set. + embedding_provider (str): The provider of the embedding service. Defaults to "openai". + embedding_model (str): The model identifier for generating embeddings. Defaults to "text-embedding-ada-002". + + Examples: + Below is a code snippet showcasing how to initialize Neo4jRM with environment variables for the database connection and OpenAI as the embedding provider: + + ```python + import os + + import dspy + import openai + + os.environ["NEO4J_URI"] = "bolt://localhost:7687" + os.environ["NEO4J_USERNAME"] = "neo4j" + os.environ["NEO4J_PASSWORD"] = "password" + os.environ["OPENAI_API_KEY"] = "sk-" + + neo4j_retriever = Neo4jRM( + index_name="myIndex", + text_node_property="text", + k=10, + embedding_provider="openai", + embedding_model="text-embedding-ada-002", + ) + + dspy.settings.configure(rm=neo4j_retriever) + ``` + + In this example, `Neo4jRM` is configured to retrieve nodes based on the "text" property from an index named "myIndex", + using embeddings computed by OpenAI's "text-embedding-ada-002" model. + """ + def __init__( self, index_name: str, @@ -96,12 +142,17 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> query_or_queries = [query_or_queries] query_vectors = self.embedder(query_or_queries) contents = [] - retrieval_query = self.retrieval_query or f"RETURN node.{self.text_node_property} AS text" + retrieval_query = self.retrieval_query or f"RETURN node.{self.text_node_property} AS text, score" for vector in query_vectors: records, _, _ = self.driver.execute_query( DEFAULT_INDEX_QUERY + retrieval_query, {"embedding": vector, "index": self.index_name, "k": k or self.k}, database_=self.database, ) - contents.extend([dotdict({"long_text": r["text"]}) for r in records]) - return contents + contents.extend([{"passage": dotdict({"long_text": r["text"]}), "score": r["score"]} for r in records]) + sorted_passages = sorted( + contents, + key=lambda x: x["score"], + reverse=True, + )[: k or self.k] + return [el["passage"] for el in sorted_passages] From 188694a55a2cb3f6e595e7a6664aa2fe954ab19d Mon Sep 17 00:00:00 2001 From: Raja Rajendran Date: Tue, 5 Mar 2024 17:58:18 +0530 Subject: [PATCH 09/79] add 'k' as argument to FaissRM.forward() --- dspy/retrieve/faiss_rm.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) mode change 100644 => 100755 dspy/retrieve/faiss_rm.py diff --git a/dspy/retrieve/faiss_rm.py b/dspy/retrieve/faiss_rm.py old mode 100644 new mode 100755 index 7a74ec4b9..37460f895 --- a/dspy/retrieve/faiss_rm.py +++ b/dspy/retrieve/faiss_rm.py @@ -3,7 +3,7 @@ """ import logging -from typing import Union +from typing import Union, Optional import numpy as np @@ -107,8 +107,8 @@ def _dump_raw_results(self, queries, index_list, distance_list) -> None: logging.debug(f" Hit {j} = {indices[j]}/{distances[j]}: {self._document_chunks[indices[j]]}") return - def forward(self, query_or_queries: Union[str, list[str]]) -> dspy.Prediction: - """Search the faiss index for self.k top passages for query. + def forward(self, query_or_queries: Union[str, list[str]], k: Optional[int] = None) -> dspy.Prediction: + """Search the faiss index for k or self.k top passages for query. Args: query_or_queries (Union[str, List[str]]): The query or queries to search for. @@ -122,13 +122,12 @@ def forward(self, query_or_queries: Union[str, list[str]]) -> dspy.Prediction: emb_npa = np.array(embeddings) # For single query, just look up the top k passages if len(queries) == 1: - distance_list, index_list = self._faiss_index.search(emb_npa, self.k) + distance_list, index_list = self._faiss_index.search(emb_npa, k or self.k) # self._dump_raw_results(queries, index_list, distance_list) passages = [(self._document_chunks[ind], ind) for ind in index_list[0]] - passages = [dotdict({"long_text": passage[0], "index": passage[1]}) for passage in passages] - return dspy.Prediction(passages=passages) + return [dotdict({"long_text": passage[0], "index": passage[1]}) for passage in passages] - distance_list, index_list = self._faiss_index.search(emb_npa, self.k * 3) + distance_list, index_list = self._faiss_index.search(emb_npa, (k or self.k) * 3) # self._dump_raw_results(queries, index_list, distance_list) passage_scores = {} for emb in range(len(embeddings)): @@ -136,7 +135,7 @@ def forward(self, query_or_queries: Union[str, list[str]]) -> dspy.Prediction: distances = distance_list[ emb ] # distances of neighbors for embeddings[emb] - this is an array of k*3 floating point numbers - for res in range(self.k * 3): + for res in range((k or self.k) * 3): neighbor = indices[res] distance = distances[res] if neighbor in passage_scores: @@ -147,10 +146,5 @@ def forward(self, query_or_queries: Union[str, list[str]]) -> dspy.Prediction: # first degree sort: number of queries that got a hit with any particular document chunk. More # is a better match. This is len(queries)-len(x[1]) # second degree sort: sum of the distances of each hit returned by faiss. Smaller distance is a better match - sorted_passages = sorted(passage_scores.items(), key=lambda x: (len(queries) - len(x[1]), sum(x[1])))[: self.k] - return dspy.Prediction( - passages=[ - dotdict({"long_text": self._document_chunks[passage_index], "index": passage_index}) - for passage_index, _ in sorted_passages - ], - ) + sorted_passages = sorted(passage_scores.items(), key=lambda x: (len(queries) - len(x[1]), sum(x[1])))[: k or self.k] + return [ dotdict({"long_text": self._document_chunks[passage_index], "index": passage_index}) for passage_index, _ in sorted_passages ] From e145529ece0edc9bd3080e456041a7cec08f548c Mon Sep 17 00:00:00 2001 From: quajak Date: Tue, 5 Mar 2024 14:30:12 -0500 Subject: [PATCH 10/79] Fix applymap deprecation warning --- dspy/evaluate/evaluate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspy/evaluate/evaluate.py b/dspy/evaluate/evaluate.py index 27358ed4f..50c1bcc21 100644 --- a/dspy/evaluate/evaluate.py +++ b/dspy/evaluate/evaluate.py @@ -140,7 +140,7 @@ def wrapped_program(example_idx, example): df = pd.DataFrame(data) # Truncate every cell in the DataFrame - df = df.applymap(truncate_cell) + df = df.map(truncate_cell) # Rename the 'correct' column to the name of the metric object assert(callable(metric)) From 3ee75d82ec6c66839326ddf7dd7e1dad1cbb81a8 Mon Sep 17 00:00:00 2001 From: Sumedha Kucherlapati Date: Tue, 5 Mar 2024 11:34:11 -0800 Subject: [PATCH 11/79] Add Claude wrapper --- dsp/modules/anthropic.py | 129 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 dsp/modules/anthropic.py diff --git a/dsp/modules/anthropic.py b/dsp/modules/anthropic.py new file mode 100644 index 000000000..99c9f225a --- /dev/null +++ b/dsp/modules/anthropic.py @@ -0,0 +1,129 @@ +import os +import backoff +import json +from typing import Optional, Any +from anthropic import Anthropic, RateLimitError + +from dsp.modules.lm import LM +import logging + + +logger = logging.getLogger(__name__) + +BASE_URL = "https://api.anthropic.com/v1/messages" + + +def backoff_hdlr(details): + """Handler from https://pypi.org/project/backoff/""" + print( + "Backing off {wait:0.1f} seconds after {tries} tries " + "calling function {target} with kwargs " + "{kwargs}".format(**details), + ) + + +def giveup_hdlr(details): + """wrapper function that decides when to give up on retry""" + if "rate limits" in details.message: + return False + return True + + +class Claude(LM): + """Wrapper around anthropic's API. Supports both the Anthropic and Azure APIs.""" + def __init__( + self, + model: str = "claude-instant-1.2", + api_key: Optional[str] = None, + api_base: Optional[str] = None, + **kwargs + ): + super().__init__(model) + self.provider = "anthropic" + self.api_key = api_key = os.environ.get("ANTHROPIC_API_KEY") if api_key is None else api_key + self.api_base = BASE_URL if api_base is None else api_base + + self.kwargs = { + "temperature": 0.0 if "temperature" not in kwargs else kwargs["temperature"], + "max_tokens": min(kwargs.get("max_tokens", 4096), 4096), + "top_p": 1.0 if "top_p" not in kwargs else kwargs["top_p"], + "top_k": 1 if "top_k" not in kwargs else kwargs["top_k"], + "n": kwargs.pop("n", kwargs.pop("num_generations", 1)), + **kwargs, + } + self.kwargs["model"] = model + self.history: list[dict[str, Any]] = [] + self.client = Anthropic(api_key=api_key) + + def log_usage(self, response): + """Log the total tokens from the Anthropic API response.""" + usage_data = response.usage + if usage_data: + total_tokens = usage_data.input_tokens + usage_data.output_tokens + logger.info(f'{total_tokens}') + + def basic_request(self, prompt: str, **kwargs): + raw_kwargs = kwargs + + kwargs = {**self.kwargs, **kwargs} + # caching mechanism requires hashable kwargs + kwargs["messages"] = [{"role": "user", "content": prompt}] + kwargs.pop("n") + print(kwargs) + response = self.client.messages.create(**kwargs) + + history = { + "prompt": prompt, + "response": response, + "kwargs": kwargs, + "raw_kwargs": raw_kwargs, + } + self.history.append(history) + + return response + + @backoff.on_exception( + backoff.expo, + (RateLimitError), + max_time=1000, + max_tries=8, + on_backoff=backoff_hdlr, + giveup=giveup_hdlr, + ) + def request(self, prompt: str, **kwargs): + """Handles retrieval of completions from Anthropic whilst handling API errors""" + return self.basic_request(prompt, **kwargs) + + def __call__(self, prompt, only_completed=True, return_sorted=False, **kwargs): + """Retrieves completions from Anthropic. + + Args: + prompt (str): prompt to send to Anthropic + only_completed (bool, optional): return only completed responses and ignores completion due to length. Defaults to True. + return_sorted (bool, optional): sort the completion choices using the returned probabilities. Defaults to False. + + Returns: + list[str]: list of completion choices + """ + + assert only_completed, "for now" + assert return_sorted is False, "for now" + + + # per eg here: https://docs.anthropic.com/claude/reference/messages-examples + # max tokens can be used as a proxy to return smaller responses + # so this cannot be a proper indicator for incomplete response unless it isnt the user-intent. + # if only_completed and response.stop_reason != "end_turn": + # choices = [] + + n = kwargs.pop("n", 1) + completions = [] + for i in range(n): + response = self.request(prompt, **kwargs) + # TODO: Log llm usage instead of hardcoded openai usage + # if dsp.settings.log_openai_usage: + # self.log_usage(response) + if only_completed and response.stop_reason == "max_tokens": + continue + completions = [c.text for c in response.content] + return completions \ No newline at end of file From 017252c5ed347c88805dc7e3d1af4183e68104e4 Mon Sep 17 00:00:00 2001 From: Sumedha Kucherlapati Date: Tue, 5 Mar 2024 11:39:09 -0800 Subject: [PATCH 12/79] project dependencies --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e2c719eaf..878601f55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "dspy-ai" -version = "2.3.6" +version = "2.3.7" description = "DSPy" readme = "README.md" authors = [{ name = "Omar Khattab", email = "okhattab@stanford.edu" }] @@ -20,6 +20,7 @@ classifiers = [ ] # We have both project and tool.poetry.dependencies. Should we remove one? dependencies = [ + "anthropic~=0.18.0", "backoff~=2.2.1", "joblib~=1.3.2", "openai>=0.28.1,<2.0.0", @@ -74,6 +75,7 @@ keywords = ["dspy", "ai", "language models", "llm", "openai"] [tool.poetry.dependencies] python = ">=3.9,<3.12" pydantic = "2.5.0" +anthropic = "^0.18.0" backoff = "^2.2.1" joblib = "^1.3.2" openai = "^0.28.1" From 0cffb585fb68645ad63b0a134c1f0a90ac13941c Mon Sep 17 00:00:00 2001 From: Sumedha Kucherlapati Date: Tue, 5 Mar 2024 11:46:51 -0800 Subject: [PATCH 13/79] Adds support to call Claude from dsp modules. --- dsp/modules/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dsp/modules/__init__.py b/dsp/modules/__init__.py index 241a349c5..06e1d6f07 100644 --- a/dsp/modules/__init__.py +++ b/dsp/modules/__init__.py @@ -13,3 +13,4 @@ from .pyserini import * from .sbert import * from .sentence_vectorizer import * +from .anthropic import Claude From 280038658bc42293cc1e92d3037665c1bcb9621b Mon Sep 17 00:00:00 2001 From: SimonB97 <102378134+SimonB97@users.noreply.github.com> Date: Wed, 6 Mar 2024 18:04:16 +0100 Subject: [PATCH 14/79] Update ProgramOfThought.md: Example Uses the extended signature syntax by utilizing a class wrapping dspy.Signature, because .attach() seems deprecated --- docs/api/modules/ProgramOfThought.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/api/modules/ProgramOfThought.md b/docs/api/modules/ProgramOfThought.md index 45814f66b..21a107902 100644 --- a/docs/api/modules/ProgramOfThought.md +++ b/docs/api/modules/ProgramOfThought.md @@ -82,11 +82,13 @@ Main method to execute the code generation and refinement process. ```python #Define a simple signature for basic question answering -generate_answer_signature = dspy.Signature("question -> answer") -generate_answer_signature.attach(question=("Question:", "")).attach(answer=("Answer:", "often between 1 and 5 words")) +class GenerateAnswer(dspy.Signature): + """Answer questions with short factoid answers.""" + question = dspy.InputField() + answer = dspy.OutputField(desc="often between 1 and 5 words") # Pass signature to ProgramOfThought Module -pot = dspy.ProgramOfThought(generate_answer_signature) +pot = dspy.ProgramOfThought(GenerateAnswer) #Call the ProgramOfThought module on a particular input question = 'Sarah has 5 apples. She buys 7 more apples from the store. How many apples does Sarah have now?' @@ -94,4 +96,4 @@ result = pot(question=question) print(f"Question: {question}") print(f"Final Predicted Answer (after ProgramOfThought process): {result.answer}") -``` \ No newline at end of file +``` From 610ad5966eec41dc21ef229e83657bc62ea89ca1 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Wed, 6 Mar 2024 21:55:18 -0800 Subject: [PATCH 15/79] refactoring optimizers, updates to optimizer notebook --- dspy/teleprompt/__init__.py | 11 +- dspy/teleprompt/copro_optimizer.py | 301 +++++++++++ dspy/teleprompt/mipro_optimizer.py | 499 +++++++++++++++++ dspy/teleprompt/signature_opt.py | 295 +--------- dspy/teleprompt/signature_opt_bayesian.py | 391 +------------- examples/qa/hotpot/hotpotqa_optimized.ipynb | 566 ++++++++++++++++++++ 6 files changed, 1390 insertions(+), 673 deletions(-) create mode 100644 dspy/teleprompt/copro_optimizer.py create mode 100644 dspy/teleprompt/mipro_optimizer.py create mode 100644 examples/qa/hotpot/hotpotqa_optimized.ipynb diff --git a/dspy/teleprompt/__init__.py b/dspy/teleprompt/__init__.py index a1088f2df..ba14c1b94 100644 --- a/dspy/teleprompt/__init__.py +++ b/dspy/teleprompt/__init__.py @@ -1,10 +1,11 @@ +from .teleprompt import * from .bootstrap import * -from .ensemble import * +from .vanilla import * +from .random_search import * from .finetune import * +from .teleprompt_optuna import * from .knn_fewshot import * -from .random_search import * from .signature_opt import SignatureOptimizer from .signature_opt_bayesian import BayesianSignatureOptimizer -from .teleprompt import * -from .teleprompt_optuna import * -from .vanilla import * +from .mipro_optimizer import MIPRO +from .copro_optimizer import COPRO \ No newline at end of file diff --git a/dspy/teleprompt/copro_optimizer.py b/dspy/teleprompt/copro_optimizer.py new file mode 100644 index 000000000..f1c303a47 --- /dev/null +++ b/dspy/teleprompt/copro_optimizer.py @@ -0,0 +1,301 @@ +from collections import defaultdict + +import dsp +import dspy +from dspy.evaluate.evaluate import Evaluate +from dspy.signatures import Signature +from dspy.teleprompt.teleprompt import Teleprompter + +""" +USAGE SUGGESTIONS: + +The following code can be used to compile a optimized signature teleprompter, and evaluate it on an end task: + +teleprompter = COPRO(prompt_model=prompt_model, metric=metric, breadth=BREADTH, depth=DEPTH, init_temperature=INIT_TEMPERATURE) +kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=0) +compiled_prompt_opt = teleprompter.compile(program.deepcopy(), devset=devset[:DEV_NUM], eval_kwargs=kwargs) +eval_score = evaluate(compiled_prompt_opt, devset=evalset[:EVAL_NUM], **kwargs) + +Note that this teleprompter takes in the following parameters: + +* prompt_model: The model used for prompt generation. When unspecified, defaults to the model set in settings (ie. dspy.settings.configure(lm=task_model)). +* metric: The task metric used for optimization. +* breadth: The number of new prompts to generate at each iteration. Default=10. +* depth: The number of times we should ask our prompt model to generate new prompts, with the history of the past prompts as input. Default=3. +* init_temperature: The temperature used to generate new prompts. Higher roughly equals more creative. Default=1.4. +* verbose: Tells the method whether or not to print intermediate steps. +* track_stats: Tells the method whether or not to track statistics about the optimization process. + If True, the method will track the following statistics: + * results_best: The min,max,avg,stddev of top 10 scores for each predictor at each depth. + * results_latest: The min,max,avg,stddev of newest prompt scores for each predictor at each depth. + * total_calls: The total number of calls to the task metric. + These statistics will be returned as attributes of the best program. +""" +class BasicGenerateInstruction(Signature): + """You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""" + + basic_instruction = dspy.InputField(desc="The initial instructions before optimization") + proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") + proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") + +class GenerateInstructionGivenAttempts(dspy.Signature): + """You are an instruction optimizer for large language models. I will give some task instructions I've tried, along with their corresponding validation scores. The instructions are arranged in increasing order based on their scores, where higher scores indicate better quality. + +Your task is to propose a new instruction that will lead a good language model to perform the task even better. Don't be afraid to be creative.""" + + attempted_instructions = dspy.InputField(format=dsp.passages2text) + proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") + proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") + +class COPRO(Teleprompter): + def __init__(self, prompt_model=None, metric=None, breadth=10, depth=3, init_temperature=1.4, verbose=False, track_stats=False): + if breadth <= 1: + raise ValueError("Breadth must be greater than 1") + self.metric = metric + self.breadth = breadth + self.depth = depth + self.init_temperature = init_temperature + self.prompt_model = prompt_model + self.verbose = verbose + self.track_stats = track_stats + + def _check_candidates_equal(self, candidate1, candidate2): + for p1, p2 in zip(candidate1["program"].predictors(), candidate2["program"].predictors()): + if self._get_signature(p1).instructions != self._get_signature(p2).instructions: + return False + *_, p1_last_field = self._get_signature(p1).fields.values() + *_, p2_last_field = self._get_signature(p2).fields.values() + if p1_last_field != p2_last_field: + return False + return True + + def _drop_duplicates(self, candidates): + final_candidates = [] + last_batch = [] + last_batch_score = -1 + for c in candidates: + repeat = False + if c['score'] == last_batch_score: + for c2 in last_batch: + if (self._check_candidates_equal(c, c2)): + repeat = True + break + if not repeat: + last_batch.append(c) + else: + last_batch = [c] + last_batch_score = c['score'] + if not repeat: + final_candidates.append(c) + return final_candidates + + def _print_signature(self, predictor): + if self.verbose: + signature = self._get_signature(predictor) + print(f"i: {signature.instructions}") + print(f"p: {list(signature.fields.values())[-1].json_schema_extra['prefix']}") + print() + + def _get_signature(self, predictor): + if (hasattr(predictor, 'extended_signature')): + return predictor.extended_signature + elif (hasattr(predictor, 'signature')): + return predictor.signature + + def _set_signature(self, predictor, updated_signature): + if (hasattr(predictor, 'extended_signature')): + predictor.extended_signature = updated_signature + elif (hasattr(predictor, 'signature')): + predictor.signature = updated_signature + + + def compile(self, student, *, devset, eval_kwargs): + """student is a program that needs to be optimized, note that it may be zero-shot or already pre-optimized for demos != []""" + module = student.deepcopy() + evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) + total_calls = 0 + results_best = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} + results_latest = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} + + if self.track_stats: + import numpy as np + + + candidates = {} + evaluated_candidates = defaultdict(dict) + + # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts + for predictor in module.predictors(): + basic_instruction = None + basic_prefix = None + *_, last_key = self._get_signature(predictor).fields.keys() + basic_instruction = self._get_signature(predictor).instructions + basic_prefix = self._get_signature(predictor).fields[last_key].json_schema_extra['prefix'] + if self.prompt_model: + with dspy.settings.context(lm=self.prompt_model): + instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) + else: + instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) + # Add in our initial prompt as a candidate as well + instruct.completions.proposed_instruction.append(basic_instruction) + instruct.completions.proposed_prefix_for_output_field.append(basic_prefix) + candidates[id(predictor)] = instruct.completions + evaluated_candidates[id(predictor)] = {} + + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + + latest_candidates = candidates + all_candidates = candidates + + module_clone = module.deepcopy() + + # For each iteration in depth... + for d in range(self.depth): # TODO: fix this so that we eval the new batch of predictors with the new best followoing predictors + if self.verbose: print(f"Starting iteration {d}/{self.depth}.") + + latest_scores = [] + + # Go through our module's predictors + for p_i, (p_old, p_new) in enumerate(zip(module.predictors(), module_clone.predictors())): + candidates_ = latest_candidates[id(p_old)] # Use the most recently generated candidates for evaluation + if len(module.predictors()) > 1: + candidates_ = all_candidates[id(p_old)] # Unless our program has multiple predictors, in which case we need to reevaluate all prompts with the new prompt(s) for the other predictor(s) + + # For each candidate + for c_i, c in enumerate(candidates_): + # Get the candidate instruction and prefix + instruction, prefix = c.proposed_instruction.strip('"').strip(), c.proposed_prefix_for_output_field.strip('"').strip() + + # Set this new module with our instruction / prefix + *_, last_key = self._get_signature(p_new).fields.keys() + updated_signature = self._get_signature(p_new) \ + .with_instructions(instruction) \ + .with_updated_fields(last_key, prefix=prefix) + self._set_signature(p_new, updated_signature) + + # Score the instruction / prefix + if self.verbose: print("----------------") + for i,predictor in enumerate(module_clone.predictors()): + if self.verbose: print(f"Predictor {i}") + self._print_signature(predictor) + if self.verbose: print(f"At Depth {d}/{self.depth}, Evaluating Prompt Candidate #{c_i}/{len(candidates_)} for Predictor {p_i} of {len(module.predictors())}.") + score = evaluate(module_clone, devset=devset, **eval_kwargs) + if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") + total_calls += 1 + if self.verbose: print("----------------") + + replace_entry = True + if self.verbose: print(f"(instruction, prefix) {(instruction, prefix)}") + # if verbose: print(f"evaluated_candidates[id(p_old)] {evaluated_candidates[id(p_old)]}") + if ((instruction, prefix) in evaluated_candidates[id(p_old)]): + # if verbose: print(f"if evaluated_candidates[id(p_old)][(instruction, prefix)] {evaluated_candidates[id(p_old)][(instruction, prefix)]}") + if evaluated_candidates[id(p_old)][(instruction, prefix)]["score"] >= score: + replace_entry = False + + if replace_entry: + # Add it to our evaluated candidates list + evaluated_candidates[id(p_old)][(instruction, prefix)] = { + "score": score, + "program": module_clone.deepcopy(), + "instruction": instruction, + "prefix": prefix, + "depth": d, + } + + if (len(candidates_)-self.breadth <= c_i): + latest_scores.append(score) + + if self.track_stats: + results_latest[id(p_old)]["depth"].append(d) + results_latest[id(p_old)]["max"].append(max(latest_scores)) + results_latest[id(p_old)]["average"].append(sum(latest_scores)/len(latest_scores)) + results_latest[id(p_old)]["min"].append(min(latest_scores)) + results_latest[id(p_old)]["std"].append(np.std(latest_scores)) + + # Now that we've evaluated the candidates, set this predictor to the best performing version + # to ensure the next round of scores reflect the best possible version + best_candidate = max(evaluated_candidates[id(p_old)].values(), key=lambda candidate: candidate['score']) + *_, last_key = self._get_signature(p_old).fields.keys() + updated_signature = self._get_signature(p_new) \ + .with_instructions(best_candidate["instruction"]) \ + .with_updated_fields(last_key, prefix=best_candidate["prefix"]) + self._set_signature(p_new, updated_signature) + if self.verbose: print(f"Updating Predictor {id(p_old)} to:\ni: {best_candidate['instruction']}\np: {best_candidate['prefix']}") + if self.verbose: print("Full predictor with update: ") + for i,predictor in enumerate(module_clone.predictors()): + if self.verbose: print(f"Predictor {i}") + self._print_signature(predictor) + + if d == self.depth-1: + break + + + new_candidates = {} + for p_base in module.predictors(): + # Build Few-Shot Example of Optimized Prompts + attempts = [] + shortest_len = self.breadth + shortest_len = min(len(evaluated_candidates[id(p_base)]),shortest_len) + best_predictors = list(evaluated_candidates[id(p_base)].values()) + + # best_predictors = evaluated_candidates[id(p_base)].values()[:] + best_predictors.sort(key=lambda x: x['score'], reverse=True) + + if self.track_stats: + scores = [x['score'] for x in best_predictors][:10] + results_best[id(p_base)]["depth"].append(d) + results_best[id(p_base)]["max"].append(max(scores)) + results_best[id(p_base)]["average"].append(sum(scores)/len(scores)) + results_best[id(p_base)]["min"].append(min(scores)) + results_best[id(p_base)]["std"].append(np.std(scores)) + + for i in range(shortest_len-1,-1,-1): + # breakpoint() + attempts.append(f'Instruction #{shortest_len-i}: {best_predictors[i]["instruction"]}') + attempts.append(f'Prefix #{shortest_len-i}: {best_predictors[i]["prefix"]}') + attempts.append(f'Resulting Score #{shortest_len-i}: {best_predictors[i]["score"]}') + + # Generate next batch of potential prompts to optimize, with previous attempts as input + if self.prompt_model: + with dspy.settings.context(lm=self.prompt_model): + instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) + else: + instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) + + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + # Get candidates for each predictor + new_candidates[id(p_base)] = instr.completions + all_candidates[id(p_base)].proposed_instruction.extend(instr.completions.proposed_instruction) + all_candidates[id(p_base)].proposed_prefix_for_output_field.extend(instr.completions.proposed_prefix_for_output_field) + + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + latest_candidates = new_candidates + + candidates = [] + for predictor in module.predictors(): + candidates.extend(list(evaluated_candidates[id(predictor)].values())) + + if self.track_stats: + best_predictors = list(evaluated_candidates[id(predictor)].values()) + best_predictors.sort(key=lambda x: x['score'], reverse=True) + + scores = [x['score'] for x in best_predictors][:10] + results_best[id(predictor)]["depth"].append(d) + results_best[id(predictor)]["max"].append(max(scores)) + results_best[id(predictor)]["average"].append(sum(scores)/len(scores)) + results_best[id(predictor)]["min"].append(min(scores)) + results_best[id(predictor)]["std"].append(np.std(scores)) + + # if verbose: print(f"candidates: {candidates}") + candidates.sort(key=lambda x: x['score'], reverse=True) + + candidates = self._drop_duplicates(candidates) + + best_program = candidates[0]["program"] + best_program.candidate_programs = candidates + best_program.total_calls = total_calls + if self.track_stats: + best_program.results_best = results_best + best_program.results_latest = results_latest + + return best_program \ No newline at end of file diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py new file mode 100644 index 000000000..5dfd691ca --- /dev/null +++ b/dspy/teleprompt/mipro_optimizer.py @@ -0,0 +1,499 @@ +import math +import random +from collections import defaultdict +import textwrap + +import optuna + +import dsp +import dspy +from dspy.evaluate.evaluate import Evaluate +from dspy.signatures import Signature +from dspy.signatures.signature import signature_to_template +from dspy.teleprompt import BootstrapFewShot +from dspy.teleprompt.teleprompt import Teleprompter +import sys +import warnings + + +""" +USAGE SUGGESTIONS: + +The following code can be used to compile a optimized signature teleprompter using the MIPROOptimizer, and evaluate it on an end task: + +from dspy.teleprompt import MIPROOptimizer + +teleprompter = MIPROOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, n=10, init_temperature=1.0) +kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=0) +compiled_prompt_opt = teleprompter.compile(program, devset=devset[:DEV_NUM], trials_num=100, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs=kwargs) +eval_score = evaluate(compiled_prompt_opt, devset=evalset[:EVAL_NUM], **kwargs) + +Note that this teleprompter takes in the following parameters: + +* prompt_model: The model used for prompt generation. When unspecified, defaults to the model set in settings (ie. dspy.settings.configure(lm=task_model)). +* task_model: The model used for prompt generation. When unspecified, defaults to the model set in settings (ie. dspy.settings.configure(lm=task_model)). +* metric: The task metric used for optimization. +* n: The number of new prompts and sets of fewshot examples to generate and evaluate. Default=10. +* init_temperature: The temperature used to generate new prompts. Higher roughly equals more creative. Default=1.0. +* verbose: Tells the method whether or not to print intermediate steps. +* track_stats: Tells the method whether or not to track statistics about the optimization process. + If True, the method will track a dictionary with a key corresponding to the trial number, + and a value containing a dict with the following keys: + * program: the program being evaluated at a given trial + * score: the last average evaluated score for the program + * pruned: whether or not this program was pruned + This information will be returned as attributes of the best program. +""" + +class BasicGenerateInstruction(Signature): + """You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""" + + basic_instruction = dspy.InputField(desc="The initial instructions before optimization") + proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") + proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") + +class BasicGenerateInstructionWithDataObservations(Signature): + """You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. I will also give you some ``observations`` I have made about the dataset and task. Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""" + + basic_instruction = dspy.InputField(desc="The initial instructions before optimization") + observations = dspy.InputField(desc="Observations about the dataset and task") + proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") + proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") + +class BasicGenerateInstructionWithExamples(dspy.Signature): + ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``examples`` of the expected inputs and outputs. + +Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""") + # attempted_instructions = dspy.InputField(format=str, desc="Previously attempted task instructions, along with their resulting validation score, and an example of the instruction in use on a sample from our dataset.") + basic_instruction = dspy.InputField(desc="The initial instructions before optimization") + # examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") + examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") + proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") + proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") + +class BasicGenerateInstructionWithExamplesAndDataObservations(dspy.Signature): + ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will give you some ``observations`` I have made about the dataset and task, along with some ``examples`` of the expected inputs and outputs. I will also provide you with the current ``basic instruction`` that is being used for this task. + +Your task is to propose a new improved instruction and prefix for the output field that will lead a good language model to perform the task well. Don't be afraid to be creative.""") + observations = dspy.InputField(desc="Observations about the dataset and task") + examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") + basic_instruction = dspy.InputField(desc="The initial instructions before optimization") + proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") + proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") + +class ObservationSummarizer(dspy.Signature): + ("""Given a series of observations I have made about my dataset, please summarize them into a brief 2-3 sentence summary which highlights only the most important details.""") + observations = dspy.InputField(desc="Observations I have made about my dataset") + summary = dspy.OutputField(desc="Two to Three sentence summary of only the most significant highlights of my observations") + +class DatasetDescriptor(dspy.Signature): + ("""Given several examples from a dataset please write observations about trends that hold for most or all of the samples. """ + """Some areas you may consider in your observations: topics, content, syntax, conciceness, etc. """ + """It will be useful to make an educated guess as to the nature of the task this dataset will enable. Don't be afraid to be creative""") + + examples = dspy.InputField(desc="Sample data points from the dataset") + observations = dspy.OutputField(desc="Somethings that holds true for most or all of the data you observed") + +class DatasetDescriptorWithPriorObservations(dspy.Signature): + ("""Given several examples from a dataset please write observations about trends that hold for most or all of the samples. """ + """I will also provide you with a few observations I have already made. Please add your own observations or if you feel the observations are comprehensive say 'COMPLETE' """ + """Some areas you may consider in your observations: topics, content, syntax, conciceness, etc. """ + """It will be useful to make an educated guess as to the nature of the task this dataset will enable. Don't be afraid to be creative""") + + examples = dspy.InputField(desc="Sample data points from the dataset") + prior_observations = dspy.InputField(desc="Some prior observations I made about the data") + observations = dspy.OutputField(desc="Somethings that holds true for most or all of the data you observed or COMPLETE if you have nothing to add") + +class MIPRO(Teleprompter): + def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): + self.n = n + self.metric = metric + self.init_temperature = init_temperature + self.prompt_model = prompt_model if prompt_model is not None else dspy.settings.lm + self.task_model = task_model if task_model is not None else dspy.settings.lm + self.verbose = verbose + self.track_stats = track_stats + self.teacher_settings = teacher_settings + self.view_data_batch_size = view_data_batch_size + + def _print_full_program(self, program): + for i,predictor in enumerate(program.predictors()): + if self.verbose: print(f"Predictor {i}") + # if self.verbose: print(f"i: {self._get_signature(predictor).instructions}") + # if self.verbose: print(f"p: {self._get_signature(predictor).fields[-1].name}") + if self.verbose: print(f"i: {self._get_signature(predictor).instructions}") + *_, last_field = self._get_signature(predictor).fields.values() + if self.verbose: print(f"p: {last_field.json_schema_extra['prefix']}") + if self.verbose: print("\n") + + def _print_model_history(self, model, n=1): + if self.verbose: print(f"Model ({model}) History:") + model.inspect_history(n=n) + + def _observe_data(self, trainset, max_iterations=10): + upper_lim = min(len(trainset), self.view_data_batch_size) + observation = dspy.Predict(DatasetDescriptor, n=1, temperature=1.0)(examples=(trainset[0:upper_lim].__repr__())) + observations = observation["observations"] + + skips = 0 + iterations = 0 + for b in range(self.view_data_batch_size, len(trainset), self.view_data_batch_size): + upper_lim = min(len(trainset), b+self.view_data_batch_size) + output = dspy.Predict(DatasetDescriptorWithPriorObservations, n=1, temperature=1.0)(prior_observations=observations, examples=(trainset[b:upper_lim].__repr__())) + iterations += 1 + if len(output["observations"]) >= 8 and output["observations"][:8].upper() == "COMPLETE": + skips += 1 + if skips >= 5: + break + continue + if iterations >= max_iterations: + break + observations += output["observations"] + + summary = dspy.Predict(ObservationSummarizer, n=1, temperature=1.0)(observations=observations) + + return summary.summary + + def _create_example_string(self, fields, example): + + # Building the output string + output = [] + for field in fields: + name = field.name + separator = field.separator + input_variable = field.input_variable + + # Determine the value from input_data or prediction_data + value = example.get(input_variable) + + # Construct the string for the current field + field_str = f"{name}{separator}{value}" + output.append(field_str) + + # Joining all the field strings + return '\n'.join(output) + + def _get_signature(self, predictor): + if (hasattr(predictor, 'extended_signature')): + return predictor.extended_signature + elif (hasattr(predictor, 'signature')): + return predictor.signature + + def _set_signature(self, predictor, updated_signature): + if (hasattr(predictor, 'extended_signature')): + predictor.extended_signature = updated_signature + elif (hasattr(predictor, 'signature')): + predictor.signature = updated_signature + + def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo_candidates, devset): + candidates = {} + evaluated_candidates = defaultdict(dict) + + if view_data: + # Create data observations + self.observations = None + with dspy.settings.context(lm=self.prompt_model): + self.observations = self._observe_data(devset).replace("Observations:","").replace("Summary:","") + + if view_examples: + example_sets = {} + for predictor in module.predictors(): + # Get all augmented examples + example_set = {} + all_sets_of_examples = demo_candidates[id(predictor)] # Get all generated sets of examples + for example_set_i, set_of_examples in enumerate(all_sets_of_examples): + if example_set_i != 0: # Skip the no examples case + for example in set_of_examples: # Get each individual example in the set + if "augmented" in example.keys(): + if example["augmented"]: + if example_set_i not in example_set: + example_set[example_set_i] = [] + fields_to_use = signature_to_template(predictor.signature).fields + input_variable_names = list(self._get_signature(predictor).input_fields.keys()) + example_string = self._create_example_string(fields_to_use, example) + example_set[example_set_i].append(example_string) + example_sets[id(predictor)] = example_set + else: + example_set[example_set_i] = [] + example_sets[id(predictor)] = example_set + + # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts + for predictor in module.predictors(): + basic_instruction = None + basic_prefix = None + basic_instruction = self._get_signature(predictor).instructions + *_, last_field = self._get_signature(predictor).fields.values() + basic_prefix = last_field.json_schema_extra["prefix"] + with dspy.settings.context(lm=self.prompt_model): + # Data & Examples + if view_data and view_examples: + if 1 not in example_sets[id(predictor)].keys(): + raise ValueError("No examples found for the given predictor") + instruct = None + for i in range(1, self.n): + new_instruct = dspy.Predict( + BasicGenerateInstructionWithExamplesAndDataObservations, + n=1, + temperature=self.init_temperature, + )( + basic_instruction=basic_instruction, + observations=self.observations, + examples=example_sets[id(predictor)][i], + ) + if not instruct: + instruct = new_instruct + else: + instruct.completions.proposed_instruction.extend(new_instruct.completions.proposed_instruction) + instruct.completions.proposed_prefix_for_output_field.extend(new_instruct.completions.proposed_prefix_for_output_field) + # Just data + elif view_data: + instruct = dspy.Predict(BasicGenerateInstructionWithDataObservations, n=N-1, temperature=self.init_temperature)(basic_instruction=basic_instruction, observations=self.observations) + # Just examples + elif view_examples: + instruct = None + for i in range(1,self.n): # Note: skip over the first example set which is empty + new_instruct = dspy.Predict( + BasicGenerateInstructionWithExamples, + n=1, + temperature=self.init_temperature, + )( + basic_instruction=basic_instruction, + examples=example_sets[id(predictor)][i], + ) + if not instruct: + instruct = new_instruct + else: + instruct.completions.proposed_instruction.extend(new_instruct.completions.proposed_instruction) + instruct.completions.proposed_prefix_for_output_field.extend(new_instruct.completions.proposed_prefix_for_output_field) + # Neither + else: + instruct = dspy.Predict(BasicGenerateInstruction, n=N-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) + + # Add in our initial prompt as a candidate as well + instruct.completions.proposed_instruction.insert(0, basic_instruction) + instruct.completions.proposed_prefix_for_output_field.insert(0, basic_prefix) + candidates[id(predictor)] = instruct.completions + evaluated_candidates[id(predictor)] = {} + + if self.verbose: self._print_model_history(self.prompt_model) + + return candidates, evaluated_candidates + + def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, trials_num=None, optuna_trials_num=None): + # Define ANSI escape codes for colors + YELLOW = '\033[93m' + BLUE = '\033[94m' + BOLD = '\033[1m' + ENDC = '\033[0m' # Resets the color to default + + # Check if both trials_num and optuna_trials_num are None + if trials_num is None and optuna_trials_num is None: + raise ValueError(f"{YELLOW}{BOLD}You must specify the number of trials using the 'trials_num' parameter.{ENDC}") + + # Check if the deprecated parameter is used + if optuna_trials_num is not None: + print("in it!") + # Issue a deprecation warning + warnings.warn( + "`trials_num` is deprecated and will be removed in a future version. " + "Use `trials_num` instead.", + DeprecationWarning + ) + # Use trials_num as a fallback if trials_num is not provided + if trials_num is None: + trials_num = optuna_trials_num + + random.seed(seed) + + estimated_task_model_calls_wo_module_calls = len(devset) * trials_num # M * T * P + estimated_prompt_model_calls = 10 + self.n * len(student.predictors()) # num data summary calls + N * P + + + + user_message = textwrap.dedent(f"""\ + {YELLOW}{BOLD}WARNING: Projected Language Model (LM) Calls{ENDC} + + Please be advised that based on the parameters you have set, the maximum number of LM calls is projected as follows: + + {YELLOW}- Task Model: {BLUE}{BOLD}{len(devset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{trials_num}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} + {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.n}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} + + {YELLOW}{BOLD}Estimated Cost Calculation:{ENDC} + + {YELLOW}Total Cost = (Number of calls to task model * (Avg Input Token Length per Call * Task Model Price per Input Token + Avg Output Token Length per Call * Task Model Price per Output Token) + + (Number of calls to prompt model * (Avg Input Token Length per Call * Task Prompt Price per Input Token + Avg Output Token Length per Call * Prompt Model Price per Output Token).{ENDC} + + For a preliminary estimate of potential costs, we recommend you perform your own calculations based on the task + and prompt models you intend to use. If the projected costs exceed your budget or expectations, you may consider: + + {YELLOW}- Reducing the number of trials (`trials_num`), the size of the trainset, or the number of LM calls in your program.{ENDC} + {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC} + + To proceed with the execution of this program, please confirm by typing {BLUE}'y'{ENDC} for yes or {BLUE}'n'{ENDC} for no. + + If you would like to bypass this confirmation step in future executions, set the {YELLOW}`requires_permission_to_run`{ENDC} flag to {YELLOW}`False`.{ENDC} + + {YELLOW}Awaiting your input...{ENDC} + """) + + print(user_message) + + sys.stdout.flush() # Flush the output buffer to force the message to print + + + if requires_permission_to_run: + user_input = input("Do you wish to continue? (y/n): ").strip().lower() + if user_input != 'y': + print("Compilation aborted by the user.") + else: + # Set up program and evaluation function + module = student.deepcopy() + evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) + + # In the case where the bootstrapped and labeled demos are set to 0, we'll stil bootstrap examples to use in our meta prompt + if max_bootstrapped_demos==0 and max_labeled_demos==0: #TODO: address case when max_bootstrapped alone is 0 + max_bootstrapped_demos_for_candidate_gen = 1 + max_labeled_demos_for_candidate_gen = 1 #TODO: this might only need to be 0 + else: + max_bootstrapped_demos_for_candidate_gen = max_bootstrapped_demos + max_labeled_demos_for_candidate_gen = max_labeled_demos + + # Generate N few shot example sets + demo_candidates = {} + for i in range(self.n): + if i == 0: # Story empty set of demos as default for index 0 + for module_p in module.predictors(): + if id(module_p) not in demo_candidates.keys(): + demo_candidates[id(module_p)] = [] + demo_candidates[id(module_p)].append([]) + else: + if self.verbose: print(f"Creating basic bootstrap: {i}/{self.n-1}") + + # Create a new basic bootstrap few - shot program . + rng = random.Random(i) + shuffled_devset = devset[:] # Create a copy of devset + rng.shuffle(shuffled_devset) # Shuffle the copy + tp = BootstrapFewShot(metric = self.metric, max_bootstrapped_demos=max_bootstrapped_demos_for_candidate_gen, max_labeled_demos=max_labeled_demos_for_candidate_gen, teacher_settings=self.teacher_settings) + candidate_program = tp.compile(student=module.deepcopy(), trainset=shuffled_devset) + + # Store the candidate demos + for module_p, candidate_p in zip(module.predictors(), candidate_program.predictors()): + if id(module_p) not in demo_candidates.keys(): + demo_candidates[id(module_p)] = [] + demo_candidates[id(module_p)].append(candidate_p.demos) + + # Generate N candidate prompts + instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, devset) + + # Reset demo_candidates to None for our optimization if the user asked for no fewshot examples + if max_bootstrapped_demos==0 and max_labeled_demos==0: + demo_candidates = None + + # Initialize variables to store the best program and its score + best_score = float('-inf') + best_program = None + trial_num = 0 + + trial_logs = {} + + # Define our trial objective + def create_objective(baseline_program, instruction_candidates, demo_candidates, evaluate, devset): + def objective(trial): + nonlocal best_program, best_score, trial_num, trial_logs # Allow access to the outer variables + candidate_program = baseline_program.deepcopy() + + # Suggest the instruction to use for our predictor + print(f"Starting trial #{trial_num}") + trial_logs[trial_num] = {} + + for p_old, p_new in zip(baseline_program.predictors(), candidate_program.predictors()): + + # Get instruction candidates for our given predictor + p_instruction_candidates = instruction_candidates[id(p_old)] + if demo_candidates: p_demo_candidates = demo_candidates[id(p_old)] + + # Suggest the index of the instruction candidate to use in our trial + instruction_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_instruction",range(len(p_instruction_candidates))) + if demo_candidates: demos_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_demos",range(len(p_demo_candidates))) + trial_logs[trial_num][f"{id(p_old)}_predictor_instruction"] = instruction_idx + if demo_candidates: trial_logs[trial_num][f"{id(p_old)}_predictor_demos"] = demos_idx + + # Get the selected instruction candidate + selected_candidate = p_instruction_candidates[instruction_idx] + selected_instruction = selected_candidate.proposed_instruction.strip('"').strip() + selected_prefix = selected_candidate.proposed_prefix_for_output_field.strip('"').strip() + + # Use this candidates in our program + *_, last_field = self._get_signature(p_new).fields.keys() + updated_signature = self._get_signature(p_new).with_instructions(selected_instruction).with_updated_fields(last_field, prefix=selected_prefix) + self._set_signature(p_new, updated_signature) + + # Get the selected demos + if demo_candidates: selected_demos = p_demo_candidates[demos_idx] + + # Use these demos in our program + if demo_candidates: p_new.demos = selected_demos + + # breakpoint() + + if self.verbose: print("Evaling the following program:") + # breakpoint() + if self.verbose: self._print_full_program(candidate_program) + trial_logs[trial_num]["program"] = candidate_program + + # Evaluate with the new prompts + total_score = 0 + batch_size = 100 + num_batches = math.ceil(len(devset) / batch_size) + + for i in range(num_batches): + start_index = i * batch_size + end_index = min((i + 1) * batch_size, len(devset)) + split_dev = devset[start_index:end_index] + split_score = evaluate(candidate_program, devset=split_dev, display_table=0) + if self.verbose: print(f"{i}st split score: {split_score}") + + total_score += split_score * len(split_dev) + curr_weighted_avg_score = total_score / min((i+1)*100,len(devset)) + if self.verbose: print(f"curr average score: {curr_weighted_avg_score}") + + trial.report(curr_weighted_avg_score, i) + + # Handle pruning based on the intermediate value. + if trial.should_prune(): + print(f"Trial pruned.") + trial_logs[trial_num]["score"] = curr_weighted_avg_score + trial_logs[trial_num]["pruned"] = True + trial_num += 1 + raise optuna.TrialPruned() + + if self.verbose: print(f"Fully evaled score: {curr_weighted_avg_score}") + if self.verbose: self._print_model_history(self.task_model, n=1) + # breakpoint() + score = curr_weighted_avg_score + + trial_logs[trial_num]["score"] = curr_weighted_avg_score + trial_logs[trial_num]["pruned"] = False + + # Update the best program if the current score is better + if score > best_score: + best_score = score + best_program = candidate_program.deepcopy() + + trial_num += 1 + + return score + + return objective + + # Run the trial + objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, devset) + sampler = optuna.samplers.TPESampler(seed=seed) + study = optuna.create_study(direction="maximize", sampler=sampler) + score = study.optimize(objective_function, n_trials=trials_num) + + if best_program is not None and self.track_stats: + best_program.trial_logs = trial_logs + + print(f"Returning {best_program} from continue_program") + return best_program \ No newline at end of file diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index e760ebf45..04da45a9c 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -1,12 +1,10 @@ -from collections import defaultdict - -import dsp -import dspy -from dspy.evaluate.evaluate import Evaluate -from dspy.signatures import Signature -from dspy.teleprompt.teleprompt import Teleprompter - +from .copro_optimizer import COPRO """ +=============================================================== +DEPRECATED!!! +PLEASE USE COPRO INSTEAD. +=============================================================== + USAGE SUGGESTIONS: The following code can be used to compile a optimized signature teleprompter, and evaluate it on an end task: @@ -31,284 +29,7 @@ * total_calls: The total number of calls to the task metric. These statistics will be returned as attributes of the best program. """ -class BasicGenerateInstruction(Signature): - """You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""" - - basic_instruction = dspy.InputField(desc="The initial instructions before optimization") - proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") - proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") - -class GenerateInstructionGivenAttempts(dspy.Signature): - """You are an instruction optimizer for large language models. I will give some task instructions I've tried, along with their corresponding validation scores. The instructions are arranged in increasing order based on their scores, where higher scores indicate better quality. -Your task is to propose a new instruction that will lead a good language model to perform the task even better. Don't be afraid to be creative.""" - - attempted_instructions = dspy.InputField(format=dsp.passages2text) - proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") - proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") - -class SignatureOptimizer(Teleprompter): +class SignatureOptimizer(COPRO): def __init__(self, prompt_model=None, metric=None, breadth=10, depth=3, init_temperature=1.4, verbose=False, track_stats=False): - if breadth <= 1: - raise ValueError("Breadth must be greater than 1") - self.metric = metric - self.breadth = breadth - self.depth = depth - self.init_temperature = init_temperature - self.prompt_model = prompt_model - self.verbose = verbose - self.track_stats = track_stats - - def _check_candidates_equal(self, candidate1, candidate2): - for p1, p2 in zip(candidate1["program"].predictors(), candidate2["program"].predictors()): - if p1.extended_signature.instructions != p2.extended_signature.instructions: - return False - *_, p1_last_field = p1.extended_signature.fields.values() - *_, p2_last_field = p2.extended_signature.fields.values() - if p1_last_field != p2_last_field: - return False - return True - - def _drop_duplicates(self, candidates): - final_candidates = [] - last_batch = [] - last_batch_score = -1 - for c in candidates: - repeat = False - if c['score'] == last_batch_score: - for c2 in last_batch: - if (self._check_candidates_equal(c, c2)): - repeat = True - break - if not repeat: - last_batch.append(c) - else: - last_batch = [c] - last_batch_score = c['score'] - if not repeat: - final_candidates.append(c) - return final_candidates - - def _print_signature(self, predictor): - if self.verbose: - if (hasattr(predictor, 'extended_signature')): - signature = predictor.extended_signature - else: - signature = predictor.extended_signature1 - print(f"i: {signature.instructions}") - print(f"p: {list(signature.fields.values())[-1].json_schema_extra['prefix']}") - print() - - - def compile(self, student, *, devset, eval_kwargs): - """student is a program that needs to be optimized, note that it may be zero-shot or already pre-optimized for demos != []""" - module = student.deepcopy() - evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) - total_calls = 0 - results_best = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} - results_latest = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} - - if self.track_stats: - import numpy as np - - - candidates = {} - evaluated_candidates = defaultdict(dict) - - # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts - for predictor in module.predictors(): - basic_instruction = None - basic_prefix = None - *_, last_key = predictor.extended_signature.fields.keys() - if (hasattr(predictor, 'extended_signature')): - basic_instruction = predictor.extended_signature.instructions - basic_prefix = predictor.extended_signature.fields[last_key].json_schema_extra['prefix'] - else: - basic_instruction = predictor.extended_signature1.instructions - basic_prefix = predictor.extended_signature1.fields[last_key].json_schema_extra['prefix'] - if self.prompt_model: - with dspy.settings.context(lm=self.prompt_model): - instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) - else: - instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) - # Add in our initial prompt as a candidate as well - instruct.completions.proposed_instruction.append(basic_instruction) - instruct.completions.proposed_prefix_for_output_field.append(basic_prefix) - candidates[id(predictor)] = instruct.completions - evaluated_candidates[id(predictor)] = {} - - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - - latest_candidates = candidates - all_candidates = candidates - - module_clone = module.deepcopy() - - # For each iteration in depth... - for d in range(self.depth): # TODO: fix this so that we eval the new batch of predictors with the new best followoing predictors - if self.verbose: print(f"Starting iteration {d}/{self.depth}.") - - latest_scores = [] - - # Go through our module's predictors - for p_i, (p_old, p_new) in enumerate(zip(module.predictors(), module_clone.predictors())): - candidates_ = latest_candidates[id(p_old)] # Use the most recently generated candidates for evaluation - if len(module.predictors()) > 1: - candidates_ = all_candidates[id(p_old)] # Unless our program has multiple predictors, in which case we need to reevaluate all prompts with the new prompt(s) for the other predictor(s) - - # For each candidate - for c_i, c in enumerate(candidates_): - # Get the candidate instruction and prefix - instruction, prefix = c.proposed_instruction.strip('"').strip(), c.proposed_prefix_for_output_field.strip('"').strip() - - # Set this new module with our instruction / prefix - if (hasattr(p_new, 'extended_signature')): - *_, last_key = p_new.extended_signature.fields.keys() - p_new.extended_signature = p_new.extended_signature \ - .with_instructions(instruction) \ - .with_updated_fields(last_key, prefix=prefix) - else: - *_, last_key = p_new.extended_signature1.fields.keys() - p_new.extended_signature1 = p_new.extended_signature1 \ - .with_instructions(instruction) \ - .with_updated_fields(last_key, prefix=prefix) - *_, last_key = p_new.extended_signature2.fields.keys() - p_new.extended_signature2 = p_new.extended_signature2 \ - .with_instructions(instruction) \ - .with_updated_fields(last_key, prefix=prefix) - - # Score the instruction / prefix - if self.verbose: print("----------------") - for i,predictor in enumerate(module_clone.predictors()): - if self.verbose: print(f"Predictor {i}") - self._print_signature(predictor) - if self.verbose: print(f"At Depth {d}/{self.depth}, Evaluating Prompt Candidate #{c_i}/{len(candidates_)} for Predictor {p_i} of {len(module.predictors())}.") - score = evaluate(module_clone, devset=devset, **eval_kwargs) - if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") - total_calls += 1 - if self.verbose: print("----------------") - - replace_entry = True - if self.verbose: print(f"(instruction, prefix) {(instruction, prefix)}") - # if verbose: print(f"evaluated_candidates[id(p_old)] {evaluated_candidates[id(p_old)]}") - if ((instruction, prefix) in evaluated_candidates[id(p_old)]): - # if verbose: print(f"if evaluated_candidates[id(p_old)][(instruction, prefix)] {evaluated_candidates[id(p_old)][(instruction, prefix)]}") - if evaluated_candidates[id(p_old)][(instruction, prefix)]["score"] >= score: - replace_entry = False - - if replace_entry: - # Add it to our evaluated candidates list - evaluated_candidates[id(p_old)][(instruction, prefix)] = { - "score": score, - "program": module_clone.deepcopy(), - "instruction": instruction, - "prefix": prefix, - "depth": d, - } - - if (len(candidates_)-self.breadth <= c_i): - latest_scores.append(score) - - if self.track_stats: - results_latest[id(p_old)]["depth"].append(d) - results_latest[id(p_old)]["max"].append(max(latest_scores)) - results_latest[id(p_old)]["average"].append(sum(latest_scores)/len(latest_scores)) - results_latest[id(p_old)]["min"].append(min(latest_scores)) - results_latest[id(p_old)]["std"].append(np.std(latest_scores)) - - # Now that we've evaluated the candidates, set this predictor to the best performing version - # to ensure the next round of scores reflect the best possible version - best_candidate = max(evaluated_candidates[id(p_old)].values(), key=lambda candidate: candidate['score']) - if (hasattr(p_new, 'extended_signature')): - *_, last_key = p_old.extended_signature.fields.keys() - p_new.extended_signature = p_new.extended_signature \ - .with_instructions(best_candidate["instruction"]) \ - .with_updated_fields(last_key, prefix=best_candidate["prefix"]) - else: - *_, last_key1 = p_old.extended_signature1.fields.keys() - p_new.extended_signature1 = p_new.extended_signature \ - .with_instructions(best_candidate["instruction"]) \ - .with_updated_fields(last_key1, prefix=best_candidate["prefix"]) - *_, last_key2 = p_old.extended_signature2.fields.keys() - p_new.extended_signature2 = p_new.extended_signature \ - .with_instructions(best_candidate["instruction"]) \ - .with_updated_fields(last_key2, prefix=best_candidate["prefix"]) - if self.verbose: print(f"Updating Predictor {id(p_old)} to:\ni: {best_candidate['instruction']}\np: {best_candidate['prefix']}") - if self.verbose: print("Full predictor with update: ") - for i,predictor in enumerate(module_clone.predictors()): - if self.verbose: print(f"Predictor {i}") - self._print_signature(predictor) - - if d == self.depth-1: - break - - - new_candidates = {} - for p_base in module.predictors(): - # Build Few-Shot Example of Optimized Prompts - attempts = [] - shortest_len = self.breadth - shortest_len = min(len(evaluated_candidates[id(p_base)]),shortest_len) - best_predictors = list(evaluated_candidates[id(p_base)].values()) - - # best_predictors = evaluated_candidates[id(p_base)].values()[:] - best_predictors.sort(key=lambda x: x['score'], reverse=True) - - if self.track_stats: - scores = [x['score'] for x in best_predictors][:10] - results_best[id(p_base)]["depth"].append(d) - results_best[id(p_base)]["max"].append(max(scores)) - results_best[id(p_base)]["average"].append(sum(scores)/len(scores)) - results_best[id(p_base)]["min"].append(min(scores)) - results_best[id(p_base)]["std"].append(np.std(scores)) - - for i in range(shortest_len-1,-1,-1): - # breakpoint() - attempts.append(f'Instruction #{shortest_len-i}: {best_predictors[i]["instruction"]}') - attempts.append(f'Prefix #{shortest_len-i}: {best_predictors[i]["prefix"]}') - attempts.append(f'Resulting Score #{shortest_len-i}: {best_predictors[i]["score"]}') - - # Generate next batch of potential prompts to optimize, with previous attempts as input - if self.prompt_model: - with dspy.settings.context(lm=self.prompt_model): - instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) - else: - instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) - - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - # Get candidates for each predictor - new_candidates[id(p_base)] = instr.completions - all_candidates[id(p_base)].proposed_instruction.extend(instr.completions.proposed_instruction) - all_candidates[id(p_base)].proposed_prefix_for_output_field.extend(instr.completions.proposed_prefix_for_output_field) - - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - latest_candidates = new_candidates - - candidates = [] - for predictor in module.predictors(): - candidates.extend(list(evaluated_candidates[id(predictor)].values())) - - if self.track_stats: - best_predictors = list(evaluated_candidates[id(predictor)].values()) - best_predictors.sort(key=lambda x: x['score'], reverse=True) - - scores = [x['score'] for x in best_predictors][:10] - results_best[id(predictor)]["depth"].append(d) - results_best[id(predictor)]["max"].append(max(scores)) - results_best[id(predictor)]["average"].append(sum(scores)/len(scores)) - results_best[id(predictor)]["min"].append(min(scores)) - results_best[id(predictor)]["std"].append(np.std(scores)) - - # if verbose: print(f"candidates: {candidates}") - candidates.sort(key=lambda x: x['score'], reverse=True) - - candidates = self._drop_duplicates(candidates) - - best_program = candidates[0]["program"] - best_program.candidate_programs = candidates - best_program.total_calls = total_calls - if self.track_stats: - best_program.results_best = results_best - best_program.results_latest = results_latest - - return best_program \ No newline at end of file + super().__init__(prompt_model, metric, breadth, depth, init_temperature, verbose, track_stats) \ No newline at end of file diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index e316462c9..a0cdd8458 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -1,18 +1,11 @@ -import math -import random -from collections import defaultdict - -import optuna - -import dsp -import dspy -from dspy.evaluate.evaluate import Evaluate -from dspy.signatures import Signature -from dspy.signatures.signature import signature_to_template -from dspy.teleprompt import BootstrapFewShot -from dspy.teleprompt.teleprompt import Teleprompter +from dspy.teleprompt.mipro_optimizer import MIPRO """ +=============================================================== +DEPRECATED!!! +PLEASE USE MIPRO INSTEAD. +=============================================================== + USAGE SUGGESTIONS: The following code can be used to compile a optimized signature teleprompter using the BayesianSignatureOptimizer, and evaluate it on an end task: @@ -40,373 +33,9 @@ * pruned: whether or not this program was pruned This information will be returned as attributes of the best program. """ -class BasicGenerateInstruction(Signature): - """You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""" - - basic_instruction = dspy.InputField(desc="The initial instructions before optimization") - proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") - proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") - -class BasicGenerateInstructionWithDataObservations(Signature): - """You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. I will also give you some ``observations`` I have made about the dataset and task. Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""" - - basic_instruction = dspy.InputField(desc="The initial instructions before optimization") - observations = dspy.InputField(desc="Observations about the dataset and task") - proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") - proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") - -class BasicGenerateInstructionWithExamples(dspy.Signature): - ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``examples`` of the expected inputs and outputs. - -Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""") - # attempted_instructions = dspy.InputField(format=str, desc="Previously attempted task instructions, along with their resulting validation score, and an example of the instruction in use on a sample from our dataset.") - basic_instruction = dspy.InputField(desc="The initial instructions before optimization") - # examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") - examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") - proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") - proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") - -class BasicGenerateInstructionWithExamplesAndDataObservations(dspy.Signature): - ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``observations`` I have made about the dataset and task, along with some ``examples`` of the expected inputs and outputs. - -Your task is to propose a new improved instruction and prefix for the output field that will lead a good language model to perform the task well. Don't be afraid to be creative.""") - basic_instruction = dspy.InputField(desc="The initial instructions before optimization") - observations = dspy.InputField(desc="Observations about the dataset and task") - examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") - proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") - proposed_prefix_for_output_field = dspy.OutputField(desc="The string at the end of the prompt, which will help the model start solving the task") - -class ObservationSummarizer(dspy.Signature): - ("""Given a series of observations I have made about my dataset, please summarize them into a brief 2-3 sentence summary which highlights only the most important details.""") - observations = dspy.InputField(desc="Observations I have made about my dataset") - summary = dspy.OutputField(desc="Two to Three sentence summary of only the most significant highlights of my observations") - -class DatasetDescriptor(dspy.Signature): - ("""Given several examples from a dataset please write observations about trends that hold for most or all of the samples. """ - """Some areas you may consider in your observations: topics, content, syntax, conciceness, etc. """ - """It will be useful to make an educated guess as to the nature of the task this dataset will enable. Don't be afraid to be creative""") - - examples = dspy.InputField(desc="Sample data points from the dataset") - observations = dspy.OutputField(desc="Somethings that holds true for most or all of the data you observed") - -class DatasetDescriptorWithPriorObservations(dspy.Signature): - ("""Given several examples from a dataset please write observations about trends that hold for most or all of the samples. """ - """I will also provide you with a few observations I have already made. Please add your own observations or if you feel the observations are comprehensive say 'COMPLETE' """ - """Some areas you may consider in your observations: topics, content, syntax, conciceness, etc. """ - """It will be useful to make an educated guess as to the nature of the task this dataset will enable. Don't be afraid to be creative""") - - examples = dspy.InputField(desc="Sample data points from the dataset") - prior_observations = dspy.InputField(desc="Some prior observations I made about the data") - observations = dspy.OutputField(desc="Somethings that holds true for most or all of the data you observed or COMPLETE if you have nothing to add") - -class BayesianSignatureOptimizer(Teleprompter): - def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=False, view_data_batch_size=10): - self.n = n - self.metric = metric - self.init_temperature = init_temperature - self.prompt_model = prompt_model if prompt_model is not None else dspy.settings.lm - self.task_model = task_model if task_model is not None else dspy.settings.lm - self.verbose = verbose - self.track_stats = track_stats - self.teacher_settings = teacher_settings - self.view_data_batch_size = view_data_batch_size - - def _print_full_program(self, program): - for i,predictor in enumerate(program.predictors()): - if self.verbose: print(f"Predictor {i}") - if (hasattr(predictor, 'extended_signature')): - if self.verbose: print(f"i: {predictor.extended_signature.instructions}") - *_, last_field = predictor.extended_signature.fields.values() - if self.verbose: print(f"p: {last_field.json_schema_extra['prefix']}") - else: - if self.verbose: print(f"i: {predictor.extended_signature1.instructions}") - *_, last_field = predictor.extended_signature1.fields.values() - if self.verbose: print(f"p: {last_field.json_schema_extra['prefix']}") - if self.verbose: print("\n") - - def _print_model_history(self, model, n=1): - if self.verbose: print(f"Model ({model}) History:") - model.inspect_history(n=n) - - def _observe_data(self, trainset): - upper_lim = min(len(trainset), self.view_data_batch_size) - observation = dspy.Predict(DatasetDescriptor, n=1, temperature=1.0)(examples=(trainset[0:upper_lim].__repr__())) - observations = observation["observations"] - - skips = 0 - for b in range(self.view_data_batch_size, len(trainset), self.view_data_batch_size): - upper_lim = min(len(trainset), b+self.view_data_batch_size) - output = dspy.Predict(DatasetDescriptorWithPriorObservations, n=1, temperature=1.0)(prior_observations=observations, examples=(trainset[b:upper_lim].__repr__())) - if len(output["observations"]) >= 8 and output["observations"][:8].upper() == "COMPLETE": - skips += 1 - if skips >= 5: - break - continue - observations += output["observations"] - - summary = dspy.Predict(ObservationSummarizer, n=1, temperature=1.0)(observations=observations) - - return summary.summary - - def _create_example_string(self, fields, example): - - # Building the output string - output = [] - for field in fields: - name = field.name - separator = field.separator - input_variable = field.input_variable - - # Determine the value from input_data or prediction_data - value = example.get(input_variable) - - # Construct the string for the current field - field_str = f"{name}{separator}{value}" - output.append(field_str) - - # Joining all the field strings - return '\n'.join(output) - - def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo_candidates, devset): - candidates = {} - evaluated_candidates = defaultdict(dict) - - if view_data: - # Create data observations - self.observations = None - with dspy.settings.context(lm=self.prompt_model): - self.observations = self._observe_data(devset).replace("Observations:","").replace("Summary:","") - - if view_examples: - example_sets = {} - for predictor in module.predictors(): - # Get all augmented examples - example_set = {} - all_sets_of_examples = demo_candidates[id(predictor)] # Get all generated sets of examples - for example_set_i, set_of_examples in enumerate(all_sets_of_examples): - if example_set_i != 0: # Skip the no examples case - for example in set_of_examples: # Get each individual example in the set - if "augmented" in example.keys(): - if example["augmented"]: - if example_set_i not in example_set: - example_set[example_set_i] = [] - fields_to_use = signature_to_template(predictor.signature).fields - input_variable_names = list(predictor.signature.input_fields.keys()) - example_with_only_signature_fields = {key: value for key, value in example.items() if key in input_variable_names} - example_string = self._create_example_string(fields_to_use, example_with_only_signature_fields) - example_set[example_set_i].append(example_string) - example_sets[id(predictor)] = example_set - else: - example_set[example_set_i] = [] - example_sets[id(predictor)] = example_set - - # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts - for predictor in module.predictors(): - basic_instruction = None - basic_prefix = None - if (hasattr(predictor, 'extended_signature')): - basic_instruction = predictor.extended_signature.instructions - *_, last_field = predictor.extended_signature.fields.values() - basic_prefix = last_field.json_schema_extra["prefix"] - else: - basic_instruction = predictor.extended_signature1.instructions - *_, last_field = predictor.extended_signature1.fields.values() - basic_prefix = last_field.json_schema_extra["prefix"] - with dspy.settings.context(lm=self.prompt_model): - # Data & Examples - if view_data and view_examples: - if 1 not in example_sets[id(predictor)].keys(): - raise ValueError("No examples found for the given predictor") - instruct = None - for i in range(1, self.n): - new_instruct = dspy.Predict( - BasicGenerateInstructionWithExamplesAndDataObservations, - n=1, - temperature=self.init_temperature, - )( - basic_instruction=basic_instruction, - observations=self.observations, - examples=example_sets[id(predictor)][i], - ) - if not instruct: - instruct = new_instruct - else: - instruct.completions.proposed_instruction.extend(new_instruct.completions.proposed_instruction) - instruct.completions.proposed_prefix_for_output_field.extend(new_instruct.completions.proposed_prefix_for_output_field) - # Just data - elif view_data: - instruct = dspy.Predict(BasicGenerateInstructionWithDataObservations, n=N-1, temperature=self.init_temperature)(basic_instruction=basic_instruction, observations=self.observations) - # Just examples - elif view_examples: - instruct = None - for i in range(1,self.n): # Note: skip over the first example set which is empty - new_instruct = dspy.Predict( - BasicGenerateInstructionWithExamples, - n=1, - temperature=self.init_temperature, - )( - basic_instruction=basic_instruction, - examples=example_sets[id(predictor)][i], - ) - if not instruct: - instruct = new_instruct - else: - instruct.completions.proposed_instruction.extend(new_instruct.completions.proposed_instruction) - instruct.completions.proposed_prefix_for_output_field.extend(new_instruct.completions.proposed_prefix_for_output_field) - # Neither - else: - instruct = dspy.Predict(BasicGenerateInstruction, n=N-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) - - # Add in our initial prompt as a candidate as well - instruct.completions.proposed_instruction.insert(0, basic_instruction) - instruct.completions.proposed_prefix_for_output_field.insert(0, basic_prefix) - candidates[id(predictor)] = instruct.completions - evaluated_candidates[id(predictor)] = {} - - if self.verbose: self._print_model_history(self.prompt_model) - - return candidates, evaluated_candidates - - def compile(self, student, *, devset, optuna_trials_num, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True): - - random.seed(seed) - - # Set up program and evaluation function - module = student.deepcopy() - evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) - - # Generate N few shot example sets - demo_candidates = {} - for i in range(self.n): - if i == 0: # Story empty set of demos as default for index 0 - for module_p in module.predictors(): - if id(module_p) not in demo_candidates: - demo_candidates[id(module_p)] = [] - demo_candidates[id(module_p)].append([]) - else: - if self.verbose: print(f"Creating basic bootstrap: {i}/{self.n-1}") - - # Create a new basic bootstrap few - shot program . - rng = random.Random(i) - shuffled_devset = devset[:] # Create a copy of devset - rng.shuffle(shuffled_devset) # Shuffle the copy - tp = BootstrapFewShot(metric = self.metric, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, teacher_settings=self.teacher_settings) - candidate_program = tp.compile(student=module.deepcopy(), trainset=shuffled_devset) - - # Store the candidate demos - for module_p, candidate_p in zip(module.predictors(), candidate_program.predictors()): - if id(module_p) not in demo_candidates: - demo_candidates[id(module_p)] = [] - demo_candidates[id(module_p)].append(candidate_p.demos) - - # Generate N candidate prompts - instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, devset) - - # Initialize variables to store the best program and its score - best_score = float('-inf') - best_program = None - trial_num = 0 - - trial_logs = {} - - # Define our trial objective - def create_objective(baseline_program, instruction_candidates, demo_candidates, evaluate, devset): - def objective(trial): - nonlocal best_program, best_score, trial_num, trial_logs # Allow access to the outer variables - candidate_program = baseline_program.deepcopy() - - # Suggest the instruction to use for our predictor - if self.verbose: print(f"Starting trial num: {trial_num}") - trial_logs[trial_num] = {} - - for p_old, p_new in zip(baseline_program.predictors(), candidate_program.predictors()): - - # Get instruction candidates for our given predictor - p_instruction_candidates = instruction_candidates[id(p_old)] - p_demo_candidates = demo_candidates[id(p_old)] - - # Suggest the index of the instruction candidate to use in our trial - #instruction_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_instruction",range(len(p_instruction_candidates))) - #demos_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_demos",range(len(p_demo_candidates))) - instruction_idx = trial.suggest_int(f"{id(p_old)}_predictor_instruction",low=0, high=len(p_instruction_candidates)-1) - demos_idx = trial.suggest_int(f"{id(p_old)}_predictor_demos",low=0, high=len(p_demo_candidates)-1) - - trial_logs[trial_num][f"{id(p_old)}_predictor_instruction"] = instruction_idx - trial_logs[trial_num][f"{id(p_old)}_predictor_demos"] = demos_idx - - # Get the selected instruction candidate - selected_candidate = p_instruction_candidates[instruction_idx] - selected_instruction = selected_candidate.proposed_instruction.strip('"').strip() - selected_prefix = selected_candidate.proposed_prefix_for_output_field.strip('"').strip() - - # Use this candidates in our program - *_, last_field = p_new.extended_signature.fields.keys() - p_new.extended_signature = p_new.extended_signature \ - .with_instructions(selected_instruction) \ - .with_updated_fields(last_field, prefix=selected_prefix) - - # Get the selected demos - selected_demos = p_demo_candidates[demos_idx] - - # Use these demos in our program - p_new.demos = selected_demos - - if self.verbose: print("Evaling the following program:") - self._print_full_program(candidate_program) - trial_logs[trial_num]["program"] = candidate_program - - # Evaluate with the new prompts - total_score = 0 - batch_size = 100 - num_batches = math.ceil(len(devset) / batch_size) - - for i in range(num_batches): - start_index = i * batch_size - end_index = min((i + 1) * batch_size, len(devset)) - split_dev = devset[start_index:end_index] - split_score = evaluate(candidate_program, devset=split_dev, display_table=0) - if self.verbose: print(f"{i}st split score: {split_score}") - - total_score += split_score * len(split_dev) - curr_weighted_avg_score = total_score / min((i+1)*100,len(devset)) - if self.verbose: print(f"curr average score: {curr_weighted_avg_score}") - - trial.report(curr_weighted_avg_score, i) - - # Handle pruning based on the intermediate value. - if trial.should_prune(): - if self.verbose: print("Optuna decided to prune!") - trial_logs[trial_num]["score"] = curr_weighted_avg_score - trial_logs[trial_num]["pruned"] = True - trial_num += 1 - raise optuna.TrialPruned() - - if self.verbose: - print(f"Fully evaled score: {curr_weighted_avg_score}") - self._print_model_history(self.task_model, n=1) - score = curr_weighted_avg_score - - trial_logs[trial_num]["score"] = curr_weighted_avg_score - trial_logs[trial_num]["pruned"] = False - - # Update the best program if the current score is better - if score > best_score: - best_score = score - best_program = candidate_program.deepcopy() - - trial_num += 1 - - return score - - return objective - - # Run the trial - objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, devset) - sampler = optuna.samplers.TPESampler(seed=seed) - study = optuna.create_study(direction="maximize", sampler=sampler) - score = study.optimize(objective_function, n_trials=optuna_trials_num) - if best_program is not None and self.track_stats: - best_program.trial_logs = trial_logs +class BayesianSignatureOptimizer(MIPRO): + def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): + print(u"\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") - return best_program + super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) \ No newline at end of file diff --git a/examples/qa/hotpot/hotpotqa_optimized.ipynb b/examples/qa/hotpot/hotpotqa_optimized.ipynb new file mode 100644 index 000000000..c87d47497 --- /dev/null +++ b/examples/qa/hotpot/hotpotqa_optimized.ipynb @@ -0,0 +1,566 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"DSPy7\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### FAQ 🙋\n", + "#### 1) How does MIPRO work?\n", + "At a high level, the MIPRO program optimizer works by first proposing candidate fewshot example sets and instructions for each prompt in your program, and then optimizing over these fewshot example sets and instructions as hyperparameters for a specified number of trials. Each trial, the optimizer evaluates different combinations of prompts on a train set, which allows it to learn which combinations yield the best performance.\n", + "\n", + "#### 2) How much will MIPRO cost me to run?\n", + "Note that __this notebook__ is free to run, because all LM calls have been cached. However, when using an optimizer on your own program, here is a breakdown of the upper bound of the number of calls to the task model and prompt model respectively:\n", + "\n", + "- **Task model calls**: MIPRO makes up to __O(TxPxM)__ task model calls, where T is the number of trials, P is the number of prompts in the program, and M is the size of the train set. This is because the model is evaluating the program on the train set each trial. In practice, this should be lower given that MIPRO tunes poor trials early (ie. it may stop a trial after running on the first 100 or so examples if performance is poor).\n", + "\n", + "- **Prompt model calls**: MIPRO makes up to N*P+10 prompt model calls, where N is the number of instruction / fewshot example set candidates to generate for each prompt, and P is the number of prompts in the program. The extra 10 calls comes from generating a summary of the data in the training set, which we use in the meta prompt to create better instructions.\n", + "\n", + "#### 3) How should I configure the hyperparameters?\n", + "We have yet to run full hyperparameter sweeps with MIPRO, but based off of initial experimintation, we'd recommend the following:\n", + "- __Trial num__: Gains can be seen after about 20-30 trials. However, 100-200 trials can help with adding on additional marginal gains.\n", + "- __n__: This hyperparameter controls the number of candidate prompts and fewshot example sets that are generated to optimize over. With more trials and less prompts to optimize, we can set n to be higher, as we have more trials to explore different combinations of prompts. If your program has between 2-3 modules and is the `num_trials=30`, we'd recommend ~`n=10`. If n is higher (say `n=100`), then we can go higher to ~`n=15`. If you have a program with only 1 module and are keeping the program 0-shot (ie. no fewshot examples), then `num_trials` should be set to equal `n`, because each trial can explore a new instruction.\n", + "- __Training set size__: Between 200 and 500 training examples are recommended. Increasing the training set size can help prevent overfitting, but adds to the expense to run.\n", + "\n", + "#### 4) What should I do if I want to reduce the cost?\n", + "You can always update hyperparameters accordingly, such as using a smaller train set, using less trials, or using a program with less modules.\n", + "Alternatively, one strategy would be to optimize using a cheaper task model (ie. locally hosted Llama-2), as initial experiments have shown that prompts optimized for a smaller model also transfer to working well on a larger model.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 0] Setup" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we'll __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from huggingface_hub import hf_hub_download\n", + "import zipfile\n", + "import os\n", + "\n", + "# Define the repository ID on Hugging Face\n", + "repo_id = 'kopsahlong/test3'\n", + "cache_file_path = hf_hub_download(repo_id=repo_id, filename='notebook_cache_v3.zip')\n", + "compiled_program_file_path = hf_hub_download(repo_id=repo_id, filename='compiled_program.pickle')\n", + "# Unzipping the file\n", + "with zipfile.ZipFile(cache_file_path, 'r') as zip_ref:\n", + " zip_ref.extractall(\".\")\n", + "\n", + "os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = \"notebook_cache\"\n", + "\n", + "\n", + "# Set up the cache for this notebook\n", + "# os.environ[\"DSP_CACHEDIR\"] = \"/lfs/0/kristaoo/dspy/examples/qa/hotpot/caches/cache_train_500_eval_500_n_10_trials_30_hops_4\" # repo_clone_path\n", + "# os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = \"/lfs/0/kristaoo/dspy/examples/qa/hotpot/caches/MIPRO_notebook_cache_v2\" # repo_clone_path\n", + "# os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = \"/lfs/0/kristaoo/dspy/notebook_cache\" # repo_clone_path\n", + "# os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = \"/lfs/0/kristaoo/dspy/examples/qa/hotpot/DSPy_notebook_cache/cache_copy\" " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pydantic version: 2.6.3\n" + ] + } + ], + "source": [ + "import pkg_resources\n", + "\n", + "# Get the version of cloudpickle\n", + "pydantic_v = pkg_resources.get_distribution(\"pydantic\").version\n", + "\n", + "print(f\"Pydantic version: {pydantic_v}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: add in DSPy setup" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will also specify the __prompt LM model__ (in this case GPT 3.5), the __task LM model__ (Llama 13B) and the retrieval model we'll be using for our task (a HotPotQA multihop retrieval task)." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "import os \n", + "import dspy\n", + "import openai\n", + "import os\n", + "\n", + "### NOTE: if you'd like to run this code without a cache, you can remove these lines to configure your OPEN AI key ###\n", + "# os.environ['OPENAI_API_KEY'] = \"TODO: ADD YOUR OPEN AI KEY HERE\"\n", + "# openai.api_key = os.environ.get('OPENAI_API_KEY')\n", + "# openai.api_base = \"https://api.openai.com/v1\"\n", + "\n", + "prompt_model_name = \"gpt-3.5-turbo-1106\"\n", + "task_model_name = \"meta-llama/Llama-2-13b-chat-hf\"\n", + "colbert_v2_endpoint = \"http://20.102.90.50:2017/wiki17_abstracts\"\n", + "\n", + "prompt_model = dspy.OpenAI(model=prompt_model_name, max_tokens=150)\n", + "task_model = dspy.HFClientTGI(model=task_model_name, port=[7140, 7141, 7142, 7143], max_tokens=150)\n", + "\n", + "colbertv2 = dspy.ColBERTv2(url=colbert_v2_endpoint)\n", + "\n", + "dspy.settings.configure(rm=colbertv2, lm=task_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1] Define Task" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we'll define the program that we'd like to run, which is a multihop [...] (we can say that it was loosely inspired by a certain paper). We additionally load in the data, and define how we'd like to evaluate this task." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/lfs/0/kristaoo/miniconda3/envs/dspy_test/lib/python3.10/site-packages/datasets/table.py:1421: FutureWarning: promote has been superseded by mode='default'.\n", + " table = cls._concat_blocks(blocks, axis=0)\n" + ] + } + ], + "source": [ + "from dspy.evaluate import Evaluate\n", + "import re \n", + "from dspy.datasets import HotPotQA\n", + "\n", + "class ReturnRankedDocuments(dspy.Signature):\n", + " \"\"\"Given a question we are trying to answer and a list of passages, return a comma separated list of the numbers associated with each passage. These numbers should be ordered by helpfulness in answering the question, with most helpful passage number first, and the least helpful last.\"\"\"\n", + " question = dspy.InputField(desc=\"The question we're trying to answer.\")\n", + " context = dspy.InputField(desc=\"List of potentially related passages.\")\n", + " ranking = dspy.OutputField(desc=\"A comma separated list of numbers corresponding to passage indices, ranked in descending order by their helpfulness in answering our question.\")\n", + "\n", + "class RankingMultiHop(dspy.Module):\n", + " def __init__(self, hops, num_passages_to_retrieve, max_passages_in_context):\n", + " super().__init__()\n", + " self.hops = hops\n", + " self.num_passages_to_retrieve = num_passages_to_retrieve\n", + " self.max_passages_in_context = max_passages_in_context\n", + " self.retrieve = dspy.Retrieve(k = self.num_passages_to_retrieve)\n", + " self.generate_query = dspy.ChainOfThought(\"context ,question->search_query\")\n", + " self.generate_answer = dspy.ChainOfThought(\"context ,question->answer\")\n", + " self.generate_ranking = dspy.ChainOfThought(ReturnRankedDocuments)\n", + " \n", + " def forward(self,question):\n", + " context = []\n", + " full_context = []\n", + " top_context = []\n", + " max_passage_num = self.max_passages_in_context\n", + " for hop in range(self.hops):\n", + " # Get a new query\n", + " query = self.generate_query(context = context, question = question).search_query\n", + " # Get new passages\n", + " context = self.retrieve(query).passages\n", + " # Add these new passages to the previous top context \n", + " full_context = top_context + context\n", + " # Get the most important indices, ranked\n", + " most_important_indices = self.generate_ranking(question=question, context=full_context).ranking\n", + " indices = [int(num) for num in re.findall(r'\\d+', most_important_indices)]\n", + "\n", + " if len(indices) < max_passage_num:\n", + " indices = range(1,max_passage_num+1)\n", + "\n", + " valid_indices = [index-1 for index in indices if index-1 < len(context)]\n", + " top_indices = sorted(valid_indices, key=lambda x: x)[:max_passage_num+1]\n", + " most_important_context_list = [context[idx] for idx in top_indices]\n", + " # Save the top context\n", + " top_context = most_important_context_list\n", + "\n", + " return dspy.Prediction(context=context, answer=self.generate_answer(context = top_context , question = question).answer)\n", + "\n", + "program = RankingMultiHop(hops=4, num_passages_to_retrieve=5, max_passages_in_context=5)\n", + "\n", + "# Load and configure the datasets.\n", + "TRAIN_SIZE = 500\n", + "EVAL_SIZE = 500\n", + "\n", + "hotpot_dataset = HotPotQA(train_seed=1, eval_seed=2023, test_size=0)\n", + "trainset = [x.with_inputs('question') for x in hotpot_dataset.train][:TRAIN_SIZE]\n", + "devset = [x.with_inputs('question') for x in hotpot_dataset.dev][:EVAL_SIZE]\n", + "\n", + "# Set up metrics\n", + "NUM_THREADS = 10\n", + "\n", + "metric = dspy.evaluate.answer_exact_match\n", + "\n", + "# kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=None)\n", + "kwargs = dict(num_threads=NUM_THREADS, display_progress=True)\n", + "evaluate = Evaluate(devset=devset, metric=metric, **kwargs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2] Baseline Evaluation\n", + "Now, we'll quickly evaluate our baseline program so that we can see how the performance using the Prompt Optimizer compares. We should see performance of about __16%__ on our trainset, and __21.4%__ on our devset." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 80 / 500 (16.0): 100%|██████████| 500/500 [00:30<00:00, 16.32it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average Metric: 80 / 500 (16.0%)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 107 / 500 (21.4): 100%|██████████| 500/500 [00:29<00:00, 17.01it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average Metric: 107 / 500 (21.4%)\n" + ] + } + ], + "source": [ + "baseline_train_score = evaluate(program,devset=trainset)\n", + "baseline_eval_score = evaluate(program, devset=devset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3] Optimizing with MIPRO" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3a] Compile Program" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import cloudpickle as pickle\n", + "from dspy.teleprompt import BayesianSignatureOptimizer\n", + "\n", + "LOAD_PRECOMPILED_PROGRAM = True\n", + "\n", + "# By default, we will load the precompiled program\n", + "if LOAD_PRECOMPILED_PROGRAM:\n", + " # Load a our precompiled program\n", + " with open(compiled_program_file_path, 'rb') as file:\n", + " # Load the data from the file\n", + " compiled_program = pickle.load(file)\n", + "# Otherwise, if desired, the program can be compiled from scratch \n", + "else:\n", + " # Define hyperparameters:\n", + " N = 10 # The number of instructions and fewshot examples that we will generate and optimize over\n", + " trials = 30 # The number of optimization trials to be run (we will test out a new combination of instructions and fewshot examples in each trial) \n", + " temperature = 1.0 # The temperature configured for generating new instructions\n", + "\n", + " # Compile\n", + " eval_kwargs = dict(num_threads=16, display_progress=True, display_table=0)\n", + " teleprompter = BayesianSignatureOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, n=N, init_temperature=temperature, verbose=True)\n", + " compiled_program = teleprompter.compile(program.deepcopy(), devset=trainset, optuna_trials_num=trials, max_bootstrapped_demos=1,max_labeled_demos=2, eval_kwargs=eval_kwargs)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "generate_query = ChainOfThought(StringSignature(context, question -> search_query\n", + " instructions='Given the fields `context`, `question`, produce the fields `search_query`.'\n", + " context = Field(annotation=str required=True json_schema_extra={'__dspy_field_type': 'input', 'prefix': 'Context:', 'desc': '${context}'})\n", + " question = Field(annotation=str required=True json_schema_extra={'__dspy_field_type': 'input', 'prefix': 'Question:', 'desc': '${question}'})\n", + " search_query = Field(annotation=str required=True json_schema_extra={'__dspy_field_type': 'output', 'prefix': 'Search Query:', 'desc': '${search_query}'})\n", + "))\n", + "generate_answer = ChainOfThought(StringSignature(context, question -> answer\n", + " instructions='Given the fields `context`, `question`, produce the fields `answer`.'\n", + " context = Field(annotation=str required=True json_schema_extra={'__dspy_field_type': 'input', 'prefix': 'Context:', 'desc': '${context}'})\n", + " question = Field(annotation=str required=True json_schema_extra={'__dspy_field_type': 'input', 'prefix': 'Question:', 'desc': '${question}'})\n", + " answer = Field(annotation=str required=True json_schema_extra={'__dspy_field_type': 'output', 'prefix': 'Answer:', 'desc': '${answer}'})\n", + "))\n", + "generate_ranking = ChainOfThought(ReturnRankedDocuments(question, context -> ranking\n", + " instructions='Given a question we are trying to answer and a list of passages, return a comma separated list of the numbers associated with each passage. These numbers should be ordered by helpfulness in answering the question, with most helpful passage number first, and the least helpful last.'\n", + " question = Field(annotation=str required=True json_schema_extra={'desc': \"The question we're trying to answer.\", '__dspy_field_type': 'input', 'prefix': 'Question:'})\n", + " context = Field(annotation=str required=True json_schema_extra={'desc': 'List of potentially related passages.', '__dspy_field_type': 'input', 'prefix': 'Context:'})\n", + " ranking = Field(annotation=str required=True json_schema_extra={'desc': 'A comma separated list of numbers corresponding to passage indices, ranked in descending order by their helpfulness in answering our question.', '__dspy_field_type': 'output', 'prefix': 'Ranking:'})\n", + "))" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "compiled_program" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3b] Evaluate optimized program" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 84 / 201 (41.8): 40%|████ | 200/500 [00:13<00:19, 15.48it/s]" + ] + } + ], + "source": [ + "bayesian_train_score = evaluate(compiled_program, devset=trainset)\n", + "bayesian_eval_score = evaluate(compiled_program, devset=devset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3c] Visualizing scores & prompts over trials" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's take a look at how this optimization looked over the course of each trial. We see that, in general, performance increases as trials go on, until it saturates after ~trial 13. Note that some of the 'pruned' trials have high scores, but were pruned early because they had comparitively lower scores on the easier slices of the data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "trial_logs = compiled_program.trial_logs\n", + "\n", + "# Extracting trial numbers, scores, and pruning status\n", + "trial_numbers = list(trial_logs.keys())\n", + "scores = [trial_logs[trial]['score'] for trial in trial_numbers]\n", + "pruning_status = [trial_logs[trial]['pruned'] for trial in trial_numbers]\n", + "\n", + "# Plot setup\n", + "plt.figure(figsize=(5, 3))\n", + "\n", + "# Plotting each point\n", + "for trial_number, score, pruned in zip(trial_numbers, scores, pruning_status):\n", + " if pruned:\n", + " plt.scatter(trial_number, score, color='grey', label='Pruned Trial' if 'Pruned Trial' not in plt.gca().get_legend_handles_labels()[1] else \"\")\n", + " else:\n", + " plt.scatter(trial_number, score, color='green', label='Successful Trial' if 'Successful Trial' not in plt.gca().get_legend_handles_labels()[1] else \"\")\n", + "\n", + "plt.xlabel('Trial Number')\n", + "plt.ylabel('Score')\n", + "plt.title('Trial Scores with Pruning Status')\n", + "plt.grid(True)\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also visualize the best prompts discovered by MIPRO as our trials progress... " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Basline program | Score: 0:\n", + "Prompt 1 Instruction: Given the fields `context`, `question`, produce the fields `search_query`.\n", + "Prompt 2 Instruction: Given the fields `context`, `question`, produce the fields `answer`.\n", + "Prompt 3 Instruction: Given a question we are trying to answer and a list of passages, return a comma separated list of the numbers associated with each passage. These numbers should be ordered by helpfulness in answering the question, with most helpful passage number first, and the least helpful last.\n", + "\n", + "----------------\n", + "Best program after 0 trials | Score: 24.0:\n", + "Prompt 1 Instruction: Given the fact-based nature of the questions related to pop culture, history, and entertainment, with a focus on identifying specific works or individuals, accurately retrieve and synthesize relevant information.\n", + "Prompt 2 Instruction: Given the fields `context` containing information about a specific topic, and `question` containing a fact-based question, generate the field `answer` with the specific information that directly addresses the question.\n", + "Prompt 3 Instruction: For a given question and list of passages, rank the passages in order of helpfulness in answering the question, with the most helpful passage first and the least helpful last. Provide a comma-separated list of the passage numbers in the ranked order.\n", + "\n", + "Best program after 5 trials | Score: 31.0:\n", + "Prompt 1 Instruction: Given the fact-based nature of the questions related to pop culture, history, and entertainment, with a focus on identifying specific works or individuals, accurately retrieve and synthesize relevant information.\n", + "Prompt 2 Instruction: Given the fields `context`, `question`, produce the fields `answer`.\n", + "Prompt 3 Instruction: Given a fact-based question, identify the specific work, individual, or event being referenced, and provide a concise and accurate answer based on the information provided in the passages.\n", + "\n", + "Best program after 10 trials | Score: 41.4:\n", + "Prompt 1 Instruction: Given the fields `context`, `question`, produce the fields `search_query`.\n", + "Prompt 2 Instruction: Given a fact-based question related to pop culture, history, or entertainment, along with a corresponding context, identify and provide a concise answer that directly corresponds to the specific question posed.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment and a list of relevant passages, identify and rank the passages in order of relevance to the question. Return a comma-separated list of the passage numbers, with the most relevant passage number first and the least relevant last.\n", + "\n", + "Best program after 15 trials | Score: 42.4:\n", + "Prompt 1 Instruction: Given the fields `context`, `question`, produce the fields `search_query`.\n", + "Prompt 2 Instruction: Given the context and question about a specific event or individual, generate a concise and precise answer that directly addresses the question.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment and a list of relevant passages, identify and rank the passages in order of relevance to the question. Return a comma-separated list of the passage numbers, with the most relevant passage number first and the least relevant last.\n", + "\n", + "Best program after 20 trials | Score: 42.4:\n", + "Prompt 1 Instruction: Given the fields `context`, `question`, produce the fields `search_query`.\n", + "Prompt 2 Instruction: Given the context and question about a specific event or individual, generate a concise and precise answer that directly addresses the question.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment and a list of relevant passages, identify and rank the passages in order of relevance to the question. Return a comma-separated list of the passage numbers, with the most relevant passage number first and the least relevant last.\n", + "\n", + "Best program after 25 trials | Score: 42.4:\n", + "Prompt 1 Instruction: Given the fields `context`, `question`, produce the fields `search_query`.\n", + "Prompt 2 Instruction: Given the context and question about a specific event or individual, generate a concise and precise answer that directly addresses the question.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment and a list of relevant passages, identify and rank the passages in order of relevance to the question. Return a comma-separated list of the passage numbers, with the most relevant passage number first and the least relevant last.\n", + "\n" + ] + } + ], + "source": [ + "best_score = 0\n", + "\n", + "def get_signature(predictor):\n", + " if (hasattr(predictor, 'extended_signature')):\n", + " return predictor.extended_signature\n", + " elif (hasattr(predictor, 'signature')):\n", + " return predictor.signature\n", + "\n", + "print(f\"Basline program | Score: {best_score}:\")\n", + "for i,predictor in enumerate(program.predictors()):\n", + " print(f\"Prompt {i+1} Instruction: {get_signature(predictor).instructions}\")\n", + "print() \n", + "\n", + "print(\"----------------\")\n", + "\n", + "for trial_num in compiled_program.trial_logs:\n", + " program_score = compiled_program.trial_logs[trial_num][\"score\"]\n", + " program_pruned = compiled_program.trial_logs[trial_num][\"pruned\"]\n", + " if program_score > best_score and not program_pruned:\n", + " best_score = program_score\n", + " best_program_so_far = compiled_program.trial_logs[trial_num][\"program\"]\n", + " if trial_num % 5 == 0:\n", + " print(f\"Best program after {trial_num} trials | Score: {best_score}:\")\n", + " for i,predictor in enumerate(best_program_so_far.predictors()):\n", + " print(f\"Prompt {i+1} Instruction: {get_signature(predictor).instructions}\")\n", + " print() " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "dspy_test", + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 3b7f285a3078c12338df9e6c45202f26a741bec6 Mon Sep 17 00:00:00 2001 From: Michael Ryan Date: Thu, 7 Mar 2024 01:06:38 -0800 Subject: [PATCH 16/79] Changed MIPRO and COPRO fields --- dspy/teleprompt/copro_optimizer.py | 8 +-- dspy/teleprompt/mipro_optimizer.py | 65 ++++++++--------------- dspy/teleprompt/signature_opt.py | 12 ++++- dspy/teleprompt/signature_opt_bayesian.py | 32 ++++++++++- 4 files changed, 69 insertions(+), 48 deletions(-) diff --git a/dspy/teleprompt/copro_optimizer.py b/dspy/teleprompt/copro_optimizer.py index f1c303a47..4cd7e3ba3 100644 --- a/dspy/teleprompt/copro_optimizer.py +++ b/dspy/teleprompt/copro_optimizer.py @@ -13,7 +13,7 @@ teleprompter = COPRO(prompt_model=prompt_model, metric=metric, breadth=BREADTH, depth=DEPTH, init_temperature=INIT_TEMPERATURE) kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=0) -compiled_prompt_opt = teleprompter.compile(program.deepcopy(), devset=devset[:DEV_NUM], eval_kwargs=kwargs) +compiled_prompt_opt = teleprompter.compile(program.deepcopy(), trainset=trainset[:DEV_NUM], eval_kwargs=kwargs) eval_score = evaluate(compiled_prompt_opt, devset=evalset[:EVAL_NUM], **kwargs) Note that this teleprompter takes in the following parameters: @@ -109,10 +109,10 @@ def _set_signature(self, predictor, updated_signature): predictor.signature = updated_signature - def compile(self, student, *, devset, eval_kwargs): + def compile(self, student, *, trainset, eval_kwargs): """student is a program that needs to be optimized, note that it may be zero-shot or already pre-optimized for demos != []""" module = student.deepcopy() - evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) + evaluate = Evaluate(devset=trainset, metric=self.metric, **eval_kwargs) total_calls = 0 results_best = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} results_latest = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} @@ -179,7 +179,7 @@ def compile(self, student, *, devset, eval_kwargs): if self.verbose: print(f"Predictor {i}") self._print_signature(predictor) if self.verbose: print(f"At Depth {d}/{self.depth}, Evaluating Prompt Candidate #{c_i}/{len(candidates_)} for Predictor {p_i} of {len(module.predictors())}.") - score = evaluate(module_clone, devset=devset, **eval_kwargs) + score = evaluate(module_clone, devset=trainset, **eval_kwargs) if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") total_calls += 1 if self.verbose: print("----------------") diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index 5dfd691ca..e96ba9d7e 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -23,9 +23,9 @@ from dspy.teleprompt import MIPROOptimizer -teleprompter = MIPROOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, n=10, init_temperature=1.0) +teleprompter = MIPROOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, num_candidates=10, init_temperature=1.0) kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=0) -compiled_prompt_opt = teleprompter.compile(program, devset=devset[:DEV_NUM], trials_num=100, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs=kwargs) +compiled_prompt_opt = teleprompter.compile(program, trainset=trainset[:TRAIN_NUM], num_trials=100, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs=kwargs) eval_score = evaluate(compiled_prompt_opt, devset=evalset[:EVAL_NUM], **kwargs) Note that this teleprompter takes in the following parameters: @@ -33,7 +33,7 @@ * prompt_model: The model used for prompt generation. When unspecified, defaults to the model set in settings (ie. dspy.settings.configure(lm=task_model)). * task_model: The model used for prompt generation. When unspecified, defaults to the model set in settings (ie. dspy.settings.configure(lm=task_model)). * metric: The task metric used for optimization. -* n: The number of new prompts and sets of fewshot examples to generate and evaluate. Default=10. +* num_candidates: The number of new prompts and sets of fewshot examples to generate and evaluate. Default=10. * init_temperature: The temperature used to generate new prompts. Higher roughly equals more creative. Default=1.0. * verbose: Tells the method whether or not to print intermediate steps. * track_stats: Tells the method whether or not to track statistics about the optimization process. @@ -105,8 +105,8 @@ class DatasetDescriptorWithPriorObservations(dspy.Signature): observations = dspy.OutputField(desc="Somethings that holds true for most or all of the data you observed or COMPLETE if you have nothing to add") class MIPRO(Teleprompter): - def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): - self.n = n + def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, num_candidates=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): + self.n = num_candidates self.metric = metric self.init_temperature = init_temperature self.prompt_model = prompt_model if prompt_model is not None else dspy.settings.lm @@ -279,43 +279,24 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo return candidates, evaluated_candidates - def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, trials_num=None, optuna_trials_num=None): + def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, num_trials=None): # Define ANSI escape codes for colors YELLOW = '\033[93m' BLUE = '\033[94m' BOLD = '\033[1m' ENDC = '\033[0m' # Resets the color to default - # Check if both trials_num and optuna_trials_num are None - if trials_num is None and optuna_trials_num is None: - raise ValueError(f"{YELLOW}{BOLD}You must specify the number of trials using the 'trials_num' parameter.{ENDC}") - - # Check if the deprecated parameter is used - if optuna_trials_num is not None: - print("in it!") - # Issue a deprecation warning - warnings.warn( - "`trials_num` is deprecated and will be removed in a future version. " - "Use `trials_num` instead.", - DeprecationWarning - ) - # Use trials_num as a fallback if trials_num is not provided - if trials_num is None: - trials_num = optuna_trials_num - random.seed(seed) - estimated_task_model_calls_wo_module_calls = len(devset) * trials_num # M * T * P + estimated_task_model_calls_wo_module_calls = len(trainset) * num_trials # M * T * P estimated_prompt_model_calls = 10 + self.n * len(student.predictors()) # num data summary calls + N * P - - user_message = textwrap.dedent(f"""\ {YELLOW}{BOLD}WARNING: Projected Language Model (LM) Calls{ENDC} Please be advised that based on the parameters you have set, the maximum number of LM calls is projected as follows: - {YELLOW}- Task Model: {BLUE}{BOLD}{len(devset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{trials_num}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} + {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{num_trials}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.n}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} {YELLOW}{BOLD}Estimated Cost Calculation:{ENDC} @@ -326,7 +307,7 @@ def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, For a preliminary estimate of potential costs, we recommend you perform your own calculations based on the task and prompt models you intend to use. If the projected costs exceed your budget or expectations, you may consider: - {YELLOW}- Reducing the number of trials (`trials_num`), the size of the trainset, or the number of LM calls in your program.{ENDC} + {YELLOW}- Reducing the number of trials (`num_trials`), the size of the trainset, or the number of LM calls in your program.{ENDC} {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC} To proceed with the execution of this program, please confirm by typing {BLUE}'y'{ENDC} for yes or {BLUE}'n'{ENDC} for no. @@ -348,7 +329,7 @@ def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, else: # Set up program and evaluation function module = student.deepcopy() - evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) + evaluate = Evaluate(devset=trainset, metric=self.metric, **eval_kwargs) # In the case where the bootstrapped and labeled demos are set to 0, we'll stil bootstrap examples to use in our meta prompt if max_bootstrapped_demos==0 and max_labeled_demos==0: #TODO: address case when max_bootstrapped alone is 0 @@ -371,10 +352,10 @@ def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, # Create a new basic bootstrap few - shot program . rng = random.Random(i) - shuffled_devset = devset[:] # Create a copy of devset - rng.shuffle(shuffled_devset) # Shuffle the copy + shuffled_trainset = trainset[:] # Create a copy of devset + rng.shuffle(shuffled_trainset) # Shuffle the copy tp = BootstrapFewShot(metric = self.metric, max_bootstrapped_demos=max_bootstrapped_demos_for_candidate_gen, max_labeled_demos=max_labeled_demos_for_candidate_gen, teacher_settings=self.teacher_settings) - candidate_program = tp.compile(student=module.deepcopy(), trainset=shuffled_devset) + candidate_program = tp.compile(student=module.deepcopy(), trainset=shuffled_trainset) # Store the candidate demos for module_p, candidate_p in zip(module.predictors(), candidate_program.predictors()): @@ -383,7 +364,7 @@ def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, demo_candidates[id(module_p)].append(candidate_p.demos) # Generate N candidate prompts - instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, devset) + instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, trainset) # Reset demo_candidates to None for our optimization if the user asked for no fewshot examples if max_bootstrapped_demos==0 and max_labeled_demos==0: @@ -397,7 +378,7 @@ def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, trial_logs = {} # Define our trial objective - def create_objective(baseline_program, instruction_candidates, demo_candidates, evaluate, devset): + def create_objective(baseline_program, instruction_candidates, demo_candidates, evaluate, trainset): def objective(trial): nonlocal best_program, best_score, trial_num, trial_logs # Allow access to the outer variables candidate_program = baseline_program.deepcopy() @@ -444,17 +425,17 @@ def objective(trial): # Evaluate with the new prompts total_score = 0 batch_size = 100 - num_batches = math.ceil(len(devset) / batch_size) + num_batches = math.ceil(len(trainset) / batch_size) for i in range(num_batches): start_index = i * batch_size - end_index = min((i + 1) * batch_size, len(devset)) - split_dev = devset[start_index:end_index] - split_score = evaluate(candidate_program, devset=split_dev, display_table=0) + end_index = min((i + 1) * batch_size, len(trainset)) + split_trainset = trainset[start_index:end_index] + split_score = evaluate(candidate_program, devset=split_trainset, display_table=0) if self.verbose: print(f"{i}st split score: {split_score}") - total_score += split_score * len(split_dev) - curr_weighted_avg_score = total_score / min((i+1)*100,len(devset)) + total_score += split_score * len(split_trainset) + curr_weighted_avg_score = total_score / min((i+1)*100,len(trainset)) if self.verbose: print(f"curr average score: {curr_weighted_avg_score}") trial.report(curr_weighted_avg_score, i) @@ -487,10 +468,10 @@ def objective(trial): return objective # Run the trial - objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, devset) + objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, trainset) sampler = optuna.samplers.TPESampler(seed=seed) study = optuna.create_study(direction="maximize", sampler=sampler) - score = study.optimize(objective_function, n_trials=trials_num) + score = study.optimize(objective_function, n_trials=num_trials) if best_program is not None and self.track_stats: best_program.trial_logs = trial_logs diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index 04da45a9c..bacd01d6c 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -1,4 +1,5 @@ from .copro_optimizer import COPRO +import warnings """ =============================================================== DEPRECATED!!! @@ -32,4 +33,13 @@ class SignatureOptimizer(COPRO): def __init__(self, prompt_model=None, metric=None, breadth=10, depth=3, init_temperature=1.4, verbose=False, track_stats=False): - super().__init__(prompt_model, metric, breadth, depth, init_temperature, verbose, track_stats) \ No newline at end of file + # warnings.warn( + # "`SignatureOptimizer` is deprecated and will be removed in a future version. " + # "Use `COPRO` instead.", + # DeprecationWarning + # ) + print(u"\u001b[31m[WARNING] SignatureOptimizer has been deprecated and replaced with COPRO. SignatureOptimizer will be removed in a future release. \u001b[31m") + super().__init__(prompt_model, metric, breadth, depth, init_temperature, verbose, track_stats) + + def compile(self, student, *, devset, eval_kwargs): + super().compile(student, trainset=devset, eval_kwargs=eval_kwargs) \ No newline at end of file diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index a4091eafa..4e6076dc5 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -1,4 +1,5 @@ from dspy.teleprompt.mipro_optimizer import MIPRO +import warnings """ =============================================================== @@ -36,6 +37,35 @@ class BayesianSignatureOptimizer(MIPRO): def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): + # warnings.warn( + # "`BayesianSignatureOptimizer` is deprecated and will be removed in a future version. " + # "Use `MIPRO` instead.", + # DeprecationWarning + # ) print(u"\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") + + super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) + + def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, trials_num=None, optuna_trials_num=None): + # Define ANSI escape codes for colors + YELLOW = '\033[93m' + BLUE = '\033[94m' + BOLD = '\033[1m' + ENDC = '\033[0m' # Resets the color to default - super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) \ No newline at end of file + # Check if both trials_num and optuna_trials_num are None + if trials_num is None and optuna_trials_num is None: + raise ValueError(f"{YELLOW}{BOLD}You must specify the number of trials using the 'trials_num' parameter.{ENDC}") + + # Check if the deprecated parameter is used + if optuna_trials_num is not None: + # Issue a deprecation warning + warnings.warn( + "`optuna_trials_num` is deprecated and will be removed in a future version. " + "Use `trials_num` instead.", + DeprecationWarning + ) + # Use trials_num as a fallback if trials_num is not provided + if trials_num is None: + trials_num = optuna_trials_num + super().compile(student, trainset=devset, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, eval_kwargs=eval_kwargs, seed=seed, view_data=view_data, view_examples=view_examples, requires_permission_to_run=requires_permission_to_run, num_trials=trials_num) \ No newline at end of file From 1a80a9bdf0c5798749f6ac21ef910a94643f2719 Mon Sep 17 00:00:00 2001 From: Michael Ryan Date: Thu, 7 Mar 2024 01:44:00 -0800 Subject: [PATCH 17/79] ensure deprecated optimizers return expected output --- dspy/teleprompt/signature_opt.py | 2 +- dspy/teleprompt/signature_opt_bayesian.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index bacd01d6c..ea4bfa61c 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -42,4 +42,4 @@ def __init__(self, prompt_model=None, metric=None, breadth=10, depth=3, init_tem super().__init__(prompt_model, metric, breadth, depth, init_temperature, verbose, track_stats) def compile(self, student, *, devset, eval_kwargs): - super().compile(student, trainset=devset, eval_kwargs=eval_kwargs) \ No newline at end of file + return super().compile(student, trainset=devset, eval_kwargs=eval_kwargs) \ No newline at end of file diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index 4e6076dc5..e1caef71d 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -68,4 +68,4 @@ def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, # Use trials_num as a fallback if trials_num is not provided if trials_num is None: trials_num = optuna_trials_num - super().compile(student, trainset=devset, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, eval_kwargs=eval_kwargs, seed=seed, view_data=view_data, view_examples=view_examples, requires_permission_to_run=requires_permission_to_run, num_trials=trials_num) \ No newline at end of file + return super().compile(student, trainset=devset, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, eval_kwargs=eval_kwargs, seed=seed, view_data=view_data, view_examples=view_examples, requires_permission_to_run=requires_permission_to_run, num_trials=trials_num) \ No newline at end of file From eb6cf859d27fe99a2cf037f81e206430249b2916 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 10:51:01 -0800 Subject: [PATCH 18/79] additonal updates to notebook, merging in refactor changes --- dspy/teleprompt/mipro_optimizer.py | 12 +- examples/qa/hotpot/hotpotqa_optimized.ipynb | 409 -------------------- 2 files changed, 6 insertions(+), 415 deletions(-) delete mode 100644 examples/qa/hotpot/hotpotqa_optimized.ipynb diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index e96ba9d7e..2580e0945 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -25,7 +25,7 @@ teleprompter = MIPROOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, num_candidates=10, init_temperature=1.0) kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=0) -compiled_prompt_opt = teleprompter.compile(program, trainset=trainset[:TRAIN_NUM], num_trials=100, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs=kwargs) +compiled_prompt_opt = teleprompter.compile(program, trainset=trainset[:TRAIN_NUM], trials_num=100, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs=kwargs) eval_score = evaluate(compiled_prompt_opt, devset=evalset[:EVAL_NUM], **kwargs) Note that this teleprompter takes in the following parameters: @@ -279,7 +279,7 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo return candidates, evaluated_candidates - def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, num_trials=None): + def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, trials_num=None): # Define ANSI escape codes for colors YELLOW = '\033[93m' BLUE = '\033[94m' @@ -288,7 +288,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo random.seed(seed) - estimated_task_model_calls_wo_module_calls = len(trainset) * num_trials # M * T * P + estimated_task_model_calls_wo_module_calls = len(trainset) * trials_num # M * T * P estimated_prompt_model_calls = 10 + self.n * len(student.predictors()) # num data summary calls + N * P user_message = textwrap.dedent(f"""\ @@ -296,7 +296,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo Please be advised that based on the parameters you have set, the maximum number of LM calls is projected as follows: - {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{num_trials}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} + {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{trials_num}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.n}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} {YELLOW}{BOLD}Estimated Cost Calculation:{ENDC} @@ -307,7 +307,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo For a preliminary estimate of potential costs, we recommend you perform your own calculations based on the task and prompt models you intend to use. If the projected costs exceed your budget or expectations, you may consider: - {YELLOW}- Reducing the number of trials (`num_trials`), the size of the trainset, or the number of LM calls in your program.{ENDC} + {YELLOW}- Reducing the number of trials (`trials_num`), the size of the trainset, or the number of LM calls in your program.{ENDC} {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC} To proceed with the execution of this program, please confirm by typing {BLUE}'y'{ENDC} for yes or {BLUE}'n'{ENDC} for no. @@ -471,7 +471,7 @@ def objective(trial): objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, trainset) sampler = optuna.samplers.TPESampler(seed=seed) study = optuna.create_study(direction="maximize", sampler=sampler) - score = study.optimize(objective_function, n_trials=num_trials) + score = study.optimize(objective_function, n_trials=trials_num) if best_program is not None and self.track_stats: best_program.trial_logs = trial_logs diff --git a/examples/qa/hotpot/hotpotqa_optimized.ipynb b/examples/qa/hotpot/hotpotqa_optimized.ipynb deleted file mode 100644 index c9b793a6a..000000000 --- a/examples/qa/hotpot/hotpotqa_optimized.ipynb +++ /dev/null @@ -1,409 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\"DSPy7\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### FAQ 🙋\n", - "#### 1) How does MIPRO work?\n", - "At a high level, the MIPRO program optimizer works by first proposing candidate fewshot example sets and instructions for each prompt in your program, and then optimizing over these fewshot example sets and instructions as hyperparameters for a specified number of trials. Each trial, the optimizer evaluates different combinations of prompts on a train set, which allows it to learn which combinations yield the best performance.\n", - "\n", - "#### 2) How much will MIPRO cost me to run?\n", - "Note that __this notebook__ is free to run, because all LM calls have been cached. However, when using an optimizer on your own program, here is a breakdown of the upper bound of the number of calls to the task model and prompt model respectively:\n", - "\n", - "- **Task model calls**: MIPRO makes up to __O(TxPxM)__ task model calls, where T is the number of trials, P is the number of prompts in the program, and M is the size of the train set. This is because the model is evaluating the program on the train set each trial. In practice, this should be lower given that MIPRO tunes poor trials early (ie. it may stop a trial after running on the first 100 or so examples if performance is poor).\n", - "\n", - "- **Prompt model calls**: MIPRO makes up to N*P+10 prompt model calls, where N is the number of instruction / fewshot example set candidates to generate for each prompt, and P is the number of prompts in the program. The extra 10 calls comes from generating a summary of the data in the training set, which we use in the meta prompt to create better instructions.\n", - "\n", - "#### 3) How should I configure the hyperparameters?\n", - "We have yet to run full hyperparameter sweeps with MIPRO, but based off of initial experimintation, we'd recommend the following:\n", - "- __Trial num__: Gains can be seen after about 20-30 trials. However, 100-200 trials can help with adding on additional marginal gains.\n", - "- __n__: This hyperparameter controls the number of candidate prompts and fewshot example sets that are generated to optimize over. With more trials and less prompts to optimize, we can set n to be higher, as we have more trials to explore different combinations of prompts. If your program has between 2-3 modules and is the `num_trials=30`, we'd recommend ~`n=10`. If n is higher (say `n=100`), then we can go higher to ~`n=15`. If you have a program with only 1 module and are keeping the program 0-shot (ie. no fewshot examples), then `num_trials` should be set to equal `n`, because each trial can explore a new instruction.\n", - "- __Training set size__: Between 200 and 500 training examples are recommended. Increasing the training set size can help prevent overfitting, but adds to the expense to run.\n", - "\n", - "#### 4) What should I do if I want to reduce the cost?\n", - "You can always update hyperparameters accordingly, such as using a smaller train set, using less trials, or using a program with less modules.\n", - "Alternatively, one strategy would be to optimize using a cheaper task model (ie. locally hosted Llama-2), as initial experiments have shown that prompts optimized for a smaller model also transfer to working well on a larger model.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 0] Setup" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, we'll __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from huggingface_hub import hf_hub_download\n", - "import zipfile\n", - "import os\n", - "\n", - "# Define the repository ID on Hugging Face\n", - "repo_id = 'kopsahlong/test3'\n", - "cache_file_path = hf_hub_download(repo_id=repo_id, filename='notebook_cache_v3.zip')\n", - "compiled_program_file_path = hf_hub_download(repo_id=repo_id, filename='compiled_program.pickle')\n", - "# Unzipping the file\n", - "with zipfile.ZipFile(cache_file_path, 'r') as zip_ref:\n", - " zip_ref.extractall(\".\")\n", - "\n", - "os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = \"notebook_cache\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# TODO: add in DSPy setup" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will also specify the __prompt LM model__ (in this case GPT 3.5), the __task LM model__ (Llama 13B) and the retrieval model we'll be using for our task (a HotPotQA multihop retrieval task)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os \n", - "import dspy\n", - "import openai\n", - "import os\n", - "\n", - "### NOTE: if you'd like to run this code without a cache, you can remove these lines to configure your OPEN AI key ###\n", - "# os.environ['OPENAI_API_KEY'] = \"TODO: ADD YOUR OPEN AI KEY HERE\"\n", - "# openai.api_key = os.environ.get('OPENAI_API_KEY')\n", - "# openai.api_base = \"https://api.openai.com/v1\"\n", - "\n", - "prompt_model_name = \"gpt-3.5-turbo-1106\"\n", - "task_model_name = \"meta-llama/Llama-2-13b-chat-hf\"\n", - "colbert_v2_endpoint = \"http://20.102.90.50:2017/wiki17_abstracts\"\n", - "\n", - "prompt_model = dspy.OpenAI(model=prompt_model_name, max_tokens=150)\n", - "task_model = dspy.HFClientTGI(model=task_model_name, port=[7140, 7141, 7142, 7143], max_tokens=150)\n", - "\n", - "colbertv2 = dspy.ColBERTv2(url=colbert_v2_endpoint)\n", - "\n", - "dspy.settings.configure(rm=colbertv2, lm=task_model)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1] Define Task" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here, we'll define the program that we'd like to run, which is a multihop [...] (we can say that it was loosely inspired by a certain paper). We additionally load in the data, and define how we'd like to evaluate this task." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from dspy.evaluate import Evaluate\n", - "import re \n", - "from dspy.datasets import HotPotQA\n", - "\n", - "class ReturnRankedDocuments(dspy.Signature):\n", - " \"\"\"Given a question we are trying to answer and a list of passages, return a comma separated list of the numbers associated with each passage. These numbers should be ordered by helpfulness in answering the question, with most helpful passage number first, and the least helpful last.\"\"\"\n", - " question = dspy.InputField(desc=\"The question we're trying to answer.\")\n", - " context = dspy.InputField(desc=\"List of potentially related passages.\")\n", - " ranking = dspy.OutputField(desc=\"A comma separated list of numbers corresponding to passage indices, ranked in descending order by their helpfulness in answering our question.\")\n", - "\n", - "class RankingMultiHop(dspy.Module):\n", - " def __init__(self, hops, num_passages_to_retrieve, max_passages_in_context):\n", - " super().__init__()\n", - " self.hops = hops\n", - " self.num_passages_to_retrieve = num_passages_to_retrieve\n", - " self.max_passages_in_context = max_passages_in_context\n", - " self.retrieve = dspy.Retrieve(k = self.num_passages_to_retrieve)\n", - " self.generate_query = dspy.ChainOfThought(\"context ,question->search_query\")\n", - " self.generate_answer = dspy.ChainOfThought(\"context ,question->answer\")\n", - " self.generate_ranking = dspy.ChainOfThought(ReturnRankedDocuments)\n", - " \n", - " def forward(self,question):\n", - " context = []\n", - " full_context = []\n", - " top_context = []\n", - " max_passage_num = self.max_passages_in_context\n", - " for hop in range(self.hops):\n", - " # Get a new query\n", - " query = self.generate_query(context = context, question = question).search_query\n", - " # Get new passages\n", - " context = self.retrieve(query).passages\n", - " # Add these new passages to the previous top context \n", - " full_context = top_context + context\n", - " # Get the most important indices, ranked\n", - " most_important_indices = self.generate_ranking(question=question, context=full_context).ranking\n", - " indices = [int(num) for num in re.findall(r'\\d+', most_important_indices)]\n", - "\n", - " if len(indices) < max_passage_num:\n", - " indices = range(1,max_passage_num+1)\n", - "\n", - " valid_indices = [index-1 for index in indices if index-1 < len(context)]\n", - " top_indices = sorted(valid_indices, key=lambda x: x)[:max_passage_num+1]\n", - " most_important_context_list = [context[idx] for idx in top_indices]\n", - " # Save the top context\n", - " top_context = most_important_context_list\n", - "\n", - " return dspy.Prediction(context=context, answer=self.generate_answer(context = top_context , question = question).answer)\n", - "\n", - "program = RankingMultiHop(hops=4, num_passages_to_retrieve=5, max_passages_in_context=5)\n", - "\n", - "# Load and configure the datasets.\n", - "TRAIN_SIZE = 500\n", - "EVAL_SIZE = 500\n", - "\n", - "hotpot_dataset = HotPotQA(train_seed=1, eval_seed=2023, test_size=0)\n", - "trainset = [x.with_inputs('question') for x in hotpot_dataset.train][:TRAIN_SIZE]\n", - "devset = [x.with_inputs('question') for x in hotpot_dataset.dev][:EVAL_SIZE]\n", - "\n", - "# Set up metrics\n", - "NUM_THREADS = 10\n", - "\n", - "metric = dspy.evaluate.answer_exact_match\n", - "\n", - "# kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=None)\n", - "kwargs = dict(num_threads=NUM_THREADS, display_progress=True)\n", - "evaluate = Evaluate(devset=devset, metric=metric, **kwargs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2] Baseline Evaluation\n", - "Now, we'll quickly evaluate our baseline program so that we can see how the performance using the Prompt Optimizer compares. We should see performance of about __16%__ on our trainset, and __21.4%__ on our devset." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "baseline_train_score = evaluate(program,devset=trainset)\n", - "baseline_eval_score = evaluate(program, devset=devset)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3] Optimizing with MIPRO" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3a] Compile Program" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import cloudpickle as pickle\n", - "from dspy.teleprompt import BayesianSignatureOptimizer\n", - "\n", - "LOAD_PRECOMPILED_PROGRAM = True\n", - "\n", - "# By default, we will load the precompiled program\n", - "if LOAD_PRECOMPILED_PROGRAM:\n", - " # Load a our precompiled program\n", - " with open(compiled_program_file_path, 'rb') as file:\n", - " # Load the data from the file\n", - " compiled_program = pickle.load(file)\n", - "# Otherwise, if desired, the program can be compiled from scratch \n", - "else:\n", - " # Define hyperparameters:\n", - " N = 10 # The number of instructions and fewshot examples that we will generate and optimize over\n", - " trials = 30 # The number of optimization trials to be run (we will test out a new combination of instructions and fewshot examples in each trial) \n", - " temperature = 1.0 # The temperature configured for generating new instructions\n", - "\n", - " # Compile\n", - " eval_kwargs = dict(num_threads=16, display_progress=True, display_table=0)\n", - " teleprompter = BayesianSignatureOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, n=N, init_temperature=temperature, verbose=True)\n", - " compiled_program = teleprompter.compile(program.deepcopy(), devset=trainset, optuna_trials_num=trials, max_bootstrapped_demos=1,max_labeled_demos=2, eval_kwargs=eval_kwargs)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "compiled_program" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3b] Evaluate optimized program" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "bayesian_train_score = evaluate(compiled_program, devset=trainset)\n", - "bayesian_eval_score = evaluate(compiled_program, devset=devset)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3c] Visualizing scores & prompts over trials" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let's take a look at how this optimization looked over the course of each trial. We see that, in general, performance increases as trials go on, until it saturates after ~trial 13. Note that some of the 'pruned' trials have high scores, but were pruned early because they had comparitively lower scores on the easier slices of the data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "trial_logs = compiled_program.trial_logs\n", - "\n", - "# Extracting trial numbers, scores, and pruning status\n", - "trial_numbers = list(trial_logs.keys())\n", - "scores = [trial_logs[trial]['score'] for trial in trial_numbers]\n", - "pruning_status = [trial_logs[trial]['pruned'] for trial in trial_numbers]\n", - "\n", - "# Plot setup\n", - "plt.figure(figsize=(5, 3))\n", - "\n", - "# Plotting each point\n", - "for trial_number, score, pruned in zip(trial_numbers, scores, pruning_status):\n", - " if pruned:\n", - " plt.scatter(trial_number, score, color='grey', label='Pruned Trial' if 'Pruned Trial' not in plt.gca().get_legend_handles_labels()[1] else \"\")\n", - " else:\n", - " plt.scatter(trial_number, score, color='green', label='Successful Trial' if 'Successful Trial' not in plt.gca().get_legend_handles_labels()[1] else \"\")\n", - "\n", - "plt.xlabel('Trial Number')\n", - "plt.ylabel('Score')\n", - "plt.title('Trial Scores with Pruning Status')\n", - "plt.grid(True)\n", - "plt.legend()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also visualize the best prompts discovered by MIPRO as our trials progress... " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "best_score = 0\n", - "\n", - "def get_signature(predictor):\n", - " if (hasattr(predictor, 'extended_signature')):\n", - " return predictor.extended_signature\n", - " elif (hasattr(predictor, 'signature')):\n", - " return predictor.signature\n", - "\n", - "print(f\"Basline program | Score: {best_score}:\")\n", - "for i,predictor in enumerate(program.predictors()):\n", - " print(f\"Prompt {i+1} Instruction: {get_signature(predictor).instructions}\")\n", - "print() \n", - "\n", - "print(\"----------------\")\n", - "\n", - "for trial_num in compiled_program.trial_logs:\n", - " program_score = compiled_program.trial_logs[trial_num][\"score\"]\n", - " program_pruned = compiled_program.trial_logs[trial_num][\"pruned\"]\n", - " if program_score > best_score and not program_pruned:\n", - " best_score = program_score\n", - " best_program_so_far = compiled_program.trial_logs[trial_num][\"program\"]\n", - " if trial_num % 5 == 0:\n", - " print(f\"Best program after {trial_num} trials | Score: {best_score}:\")\n", - " for i,predictor in enumerate(best_program_so_far.predictors()):\n", - " print(f\"Prompt {i+1} Instruction: {get_signature(predictor).instructions}\")\n", - " print() " - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "dspy_test", - "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" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From d366d629b0ecea51d4e2f5c736e54fe8c7ba20cb Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 10:52:04 -0800 Subject: [PATCH 19/79] updates to notebook --- examples/qa/hotpot/hotpotqa_optimized.ipynb | 666 ++++++++++++++++++++ 1 file changed, 666 insertions(+) create mode 100644 examples/qa/hotpot/hotpotqa_optimized.ipynb diff --git a/examples/qa/hotpot/hotpotqa_optimized.ipynb b/examples/qa/hotpot/hotpotqa_optimized.ipynb new file mode 100644 index 000000000..e97102d97 --- /dev/null +++ b/examples/qa/hotpot/hotpotqa_optimized.ipynb @@ -0,0 +1,666 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "li3F9kMOqZHz" + }, + "source": [ + "\"DSPy7" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3wEDck3ZqZH0" + }, + "source": [ + "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7DzBCQ0UqZH0" + }, + "source": [ + "### FAQ 🙋\n", + "#### 1) How does MIPRO work?\n", + "At a high level, the MIPRO program optimizer works by first __proposing__ candidate fewshot example sets and instructions for each prompt in your program, and then __optimizing__ over these fewshot example sets and instructions as hyperparameters for a specified number of trials. Each trial, the optimizer evaluates different combinations of prompts on a train set, which allows it to learn which combinations yield the best performance.\n", + "\n", + "#### 2) How much will MIPRO cost me to run?\n", + "Note that __this notebook__ is free to run, because all LM calls have been cached. However, when using an optimizer on your own program, here is a breakdown of the upper bound of the number of calls to the task model and prompt model respectively:\n", + "\n", + "- **Task model calls**: MIPRO makes up to __O(TxPxM)__ task model calls, where T is the number of trials, P is the number of prompts in the program, and M is the size of the train set. This is because the model is evaluating the program on the train set each trial. In practice, this should be lower given that MIPRO tunes poor trials early (ie. it may stop a trial after running on the first 100 or so examples if performance is poor).\n", + "\n", + "- **Prompt model calls**: MIPRO makes up to N*P+10 prompt model calls, where N is the number of instruction / fewshot example set candidates to generate for each prompt, and P is the number of prompts in the program. The extra 10 calls comes from generating a summary of the data in the training set, which we use in the meta prompt to create better instructions.\n", + "\n", + "#### 3) How should I configure the hyperparameters?\n", + "We have yet to run full hyperparameter sweeps with MIPRO, but based off of initial experimintation, we'd recommend the following:\n", + "- __Trial num__: Gains can be seen after about 20-30 trials. However, 100-200 trials can help with adding on additional marginal gains.\n", + "- __n__: This hyperparameter controls the number of candidate prompts and fewshot example sets that are generated to optimize over. With more trials and less prompts to optimize, we can set n to be higher, as we have more trials to explore different combinations of prompts. If your program has between 2-3 modules and is the `num_trials=30`, we'd recommend ~`n=10`. If n is higher (say `n=100`), then we can go higher to ~`n=15`. If you have a program with only 1 module and are keeping the program 0-shot (ie. no fewshot examples), then `num_trials` should be set to equal `n`, because each trial can explore a new instruction.\n", + "- __Training set size__: Between 200 and 500 training examples are recommended. Increasing the training set size can help prevent overfitting, but adds to the expense to run.\n", + "\n", + "#### 4) What should I do if I want to reduce the cost?\n", + "You can always update hyperparameters accordingly, such as using a smaller train set, using less trials, or using a program with less modules.\n", + "Alternatively, one strategy would be to optimize using a cheaper task model (ie. locally hosted Llama-2), as initial experiments have shown that prompts optimized for a smaller model also transfer to working well on a larger model.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SgTc-CutqZH1" + }, + "source": [ + "### 0] Setup" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rbGIXWcqqZH1" + }, + "source": [ + "First, we'll __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook. We'll also load in our pre optimized program from hugging face to inspect later." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "l4Fsh7EhqZH1", + "outputId": "bc43f9ad-e090-4e5d-bd54-1e998225b44d" + }, + "outputs": [], + "source": [ + "from huggingface_hub import hf_hub_download\n", + "import zipfile\n", + "import os\n", + "\n", + "repo_id = 'kopsahlong/DSPy_MIPRO_notebook_cache'\n", + "cache_file_path = hf_hub_download(repo_id=repo_id, filename='MIPRO_notebook_cache.zip')\n", + "compiled_program_file_path = hf_hub_download(repo_id=repo_id, filename='compiled_program.pickle')\n", + "with zipfile.ZipFile(cache_file_path, 'r') as zip_ref:\n", + " zip_ref.extractall(\".\")\n", + "os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = f\"{os.getcwd()}/MIPRO_notebook_cache\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5Vo4Tb9srSow" + }, + "source": [ + "Next, we will install __DSPy__ if it's not there already." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JpijP_d7qZH2", + "outputId": "daf24b9e-7030-4bf1-a08f-ff8b4ad42e22" + }, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import sys\n", + "import os\n", + "import regex as re\n", + "\n", + "try: # When on google Colab, let's clone the notebook so we download the cache.\n", + " import google.colab\n", + " repo_path = 'dspy'\n", + "\n", + " !git -C $repo_path pull origin || git clone https://github.com/stanfordnlp/dspy $repo_path\n", + "except:\n", + " repo_path = '.'\n", + "\n", + "if repo_path not in sys.path:\n", + " sys.path.append(repo_path)\n", + "\n", + "\n", + "import pkg_resources # Install the package if it's not installed\n", + "if not \"dspy-ai\" in {pkg.key for pkg in pkg_resources.working_set}:\n", + " !pip install -U pip\n", + " !pip install dspy-ai\n", + " !pip install openai~=0.28.1\n", + " !pip install -e $repo_path\n", + " !pip install --upgrade cloudpickle==3.0.0\n", + "\n", + "import dspy" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "U-DaFCBvqZH2" + }, + "source": [ + "We will also specify the __prompt LM model__ (in this case GPT 3.5), the __task LM model__ (Llama 13B) and the retrieval model we'll be using for our task (a HotPotQA multihop retrieval task)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "UHWzGRVgqZH2" + }, + "outputs": [], + "source": [ + "### NOTE: if you'd like to run this code without a cache, you can remove these lines to configure your OPEN AI key ###\n", + "# os.environ['OPENAI_API_KEY'] = \"TODO: ADD YOUR OPEN AI KEY HERE\"\n", + "# openai.api_key = os.environ.get('OPENAI_API_KEY')\n", + "# openai.api_base = \"https://api.openai.com/v1\"\n", + "\n", + "prompt_model_name = \"gpt-3.5-turbo-1106\"\n", + "task_model_name = \"meta-llama/Llama-2-13b-chat-hf\"\n", + "colbert_v2_endpoint = \"http://20.102.90.50:2017/wiki17_abstracts\"\n", + "\n", + "prompt_model = dspy.OpenAI(model=prompt_model_name, max_tokens=150)\n", + "task_model = dspy.HFClientTGI(model=task_model_name, port=[7140, 7141, 7142, 7143], max_tokens=150)\n", + "\n", + "colbertv2 = dspy.ColBERTv2(url=colbert_v2_endpoint)\n", + "\n", + "dspy.settings.configure(rm=colbertv2, lm=task_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BFoPwDrUqZH2" + }, + "source": [ + "### 1] Define Task" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s4Cyb1JtqZH2" + }, + "source": [ + "Here, we'll define the program that we'd like to run, which is a multihop [...] (we can say that it was loosely inspired by a certain paper). We additionally load in the data, and define how we'd like to evaluate this task." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hiVgd3N7qZH3", + "outputId": "09e1ea66-7c8d-438a-8c37-1ab96fe8cdf0" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/lfs/0/kristaoo/miniconda3/envs/dspy_test/lib/python3.10/site-packages/datasets/table.py:1421: FutureWarning: promote has been superseded by mode='default'.\n", + " table = cls._concat_blocks(blocks, axis=0)\n" + ] + } + ], + "source": [ + "import re\n", + "from dspy.evaluate import Evaluate\n", + "from dspy.datasets import HotPotQA\n", + "from dsp.utils import EM\n", + "\n", + "class ReturnRankedDocuments(dspy.Signature):\n", + " \"\"\"Given a question we are trying to answer and a list of passages, return a comma separated list of the numbers associated with each passage. These numbers should be ordered by helpfulness in answering the question, with most helpful passage number first, and the least helpful last.\"\"\"\n", + " question = dspy.InputField(desc=\"The question we're trying to answer.\")\n", + " context = dspy.InputField(desc=\"List of potentially related passages.\")\n", + " ranking = dspy.OutputField(desc=\"A comma separated list of numbers corresponding to passage indices, ranked in descending order by their helpfulness in answering our question.\")\n", + "\n", + "class RankingMultiHop(dspy.Module):\n", + " def __init__(self, hops, num_passages_to_retrieve, max_passages_in_context):\n", + " super().__init__()\n", + " self.hops = hops\n", + " self.num_passages_to_retrieve = num_passages_to_retrieve\n", + " self.max_passages_in_context = max_passages_in_context\n", + " self.retrieve = dspy.Retrieve(k = self.num_passages_to_retrieve)\n", + " self.generate_query = dspy.ChainOfThought(\"context ,question->search_query\")\n", + " self.generate_answer = dspy.ChainOfThought(\"context ,question->answer\")\n", + " self.generate_ranking = dspy.ChainOfThought(ReturnRankedDocuments)\n", + "\n", + " def forward(self,question):\n", + " context = []\n", + " full_context = []\n", + " top_context = []\n", + " max_passage_num = self.max_passages_in_context\n", + " for hop in range(self.hops):\n", + " # Get a new query\n", + " query = self.generate_query(context = context, question = question).search_query\n", + " # Get new passages\n", + " context = self.retrieve(query).passages\n", + " # Add these new passages to the previous top context\n", + " full_context = top_context + context\n", + " # Get the most important indices, ranked\n", + " most_important_indices = self.generate_ranking(question=question, context=full_context).ranking\n", + " indices = [int(num) for num in re.findall(r'\\d+', most_important_indices)]\n", + "\n", + " if len(indices) < max_passage_num:\n", + " indices = range(1,max_passage_num+1)\n", + "\n", + " valid_indices = [index-1 for index in indices if index-1 < len(context)]\n", + " top_indices = sorted(valid_indices, key=lambda x: x)[:max_passage_num+1]\n", + " most_important_context_list = [context[idx] for idx in top_indices]\n", + " # Save the top context\n", + " top_context = most_important_context_list\n", + "\n", + " return dspy.Prediction(context=context, answer=self.generate_answer(context = top_context , question = question).answer)\n", + "\n", + "program = RankingMultiHop(hops=4, num_passages_to_retrieve=5, max_passages_in_context=5)\n", + "\n", + "# Load and configure the datasets.\n", + "TRAIN_SIZE = 500\n", + "EVAL_SIZE = 500\n", + "\n", + "hotpot_dataset = HotPotQA(train_seed=1, eval_seed=2023, test_size=0)\n", + "trainset = [x.with_inputs('question') for x in hotpot_dataset.train][:TRAIN_SIZE]\n", + "devset = [x.with_inputs('question') for x in hotpot_dataset.dev][:EVAL_SIZE]\n", + "\n", + "# Set up metrics\n", + "NUM_THREADS = 10\n", + "\n", + "metric = dspy.evaluate.answer_exact_match\n", + "\n", + "kwargs = dict(num_threads=NUM_THREADS, display_progress=True)\n", + "evaluate = Evaluate(devset=devset, metric=metric, **kwargs)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hRGld1C1qZH3" + }, + "source": [ + "### 2] Baseline Evaluation\n", + "Now, we'll quickly evaluate our baseline program so that we can see how the performance using the Prompt Optimizer compares. We should see performance of about __21.6%__ on our trainset, and __22.6%__ on our devset." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "MU2aHQBTqZH3", + "outputId": "fd60fbb3-ca89-4ecb-911b-24751f220cc6" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 108 / 500 (21.6): 100%|██████████| 500/500 [00:33<00:00, 14.90it/s]\n", + "/lfs/0/kristaoo/dspy/dspy/evaluate/evaluate.py:145: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n", + " df = df.applymap(truncate_cell)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average Metric: 108 / 500 (21.6%)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 113 / 500 (22.6): 100%|██████████| 500/500 [00:33<00:00, 15.00it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average Metric: 113 / 500 (22.6%)\n" + ] + } + ], + "source": [ + "baseline_train_score = evaluate(program,devset=trainset)\n", + "baseline_eval_score = evaluate(program, devset=devset)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cjCoL27yqZH3" + }, + "source": [ + "### 3] Optimizing with MIPRO" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eEGOKjXprc7z" + }, + "source": [ + "Now let's get into the key method in this notebook - optimizing our program with MIPRO!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "G04L5j9iqZH3" + }, + "source": [ + "#### 3a] Compile Program\n", + "First, we'll get our optimized program. By default, we set `LOAD_PRECOMPILED_PROGRAM` to `True`, so that you can quickly access a program we've precompiled for you. However, if you wish to optimize yourself, `LOAD_PRECOMPILED_PROGRAM` can be set to `False` (though please note that this will require adding in your own LM API keys in the __Setup__ section above).\n", + "\n", + "MIPRO only needs a metric, DSPy module, and training set to see huge gains on your task! You can instantiate a MIPRO Optimizer and compile in just two lines:\n", + "```python\n", + "teleprompter = BayesianSignatureOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, num_candidates=N, init_temperature=temperature)\n", + "compiled_program = teleprompter.compile(program, trainset=trainset, num_trials=trials, max_bootstrapped_demos=1,max_labeled_demos=2, eval_kwargs=eval_kwargs)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "TpFW7IaYqZH3", + "outputId": "7125bbed-b79e-4178-c390-fc81cc698106" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/lfs/0/kristaoo/dspy/examples/qa/hotpot/MIPRO_notebook_cache/compiler\n" + ] + } + ], + "source": [ + "import cloudpickle as pickle\n", + "from dspy.teleprompt import BayesianSignatureOptimizer\n", + "\n", + "LOAD_PRECOMPILED_PROGRAM = True\n", + "\n", + "# By default, we will load the precompiled program\n", + "if LOAD_PRECOMPILED_PROGRAM:\n", + " # Load a our precompiled program\n", + " with open(compiled_program_file_path, 'rb') as file:\n", + " # Load the data from the file\n", + " compiled_program = pickle.load(file)\n", + "# Otherwise, if desired, the program can be compiled from scratch\n", + "else:\n", + " # Define hyperparameters:\n", + " N = 10 # The number of instructions and fewshot examples that we will generate and optimize over\n", + " trials = 30 # The number of optimization trials to be run (we will test out a new combination of instructions and fewshot examples in each trial) \n", + " temperature = 1.0 # The temperature configured for generating new instructions\n", + "\n", + " # Compile\n", + " eval_kwargs = dict(num_threads=16, display_progress=True, display_table=0)\n", + " teleprompter = MIPRO(prompt_model=prompt_model, task_model=task_model, metric=metric, num_candidates=N, init_temperature=temperature, verbose=True)\n", + " compiled_program = teleprompter.compile(program, trainset=trainset, trials_num=trials, max_bootstrapped_demos=1,max_labeled_demos=2, eval_kwargs=eval_kwargs)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uqVVnaEBqZH3" + }, + "source": [ + "#### 3b] Evaluate optimized program\n", + "Now, we evaluate our program that has been optimized with MIPRO. We see that performance on train and dev have improved by __+20pt__ and __+17.8pt__ respectively!" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VvnBp7huqZH3", + "outputId": "fdba6cfe-51b4-4ea1-f5af-9c2a5fed2064" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 208 / 500 (41.6): 100%|██████████| 500/500 [00:32<00:00, 15.27it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average Metric: 208 / 500 (41.6%)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 202 / 500 (40.4): 100%|██████████| 500/500 [00:33<00:00, 15.04it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average Metric: 202 / 500 (40.4%)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "bayesian_train_score = evaluate(compiled_program, devset=trainset)\n", + "bayesian_eval_score = evaluate(compiled_program, devset=devset)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j3UWn_UnqZH4" + }, + "source": [ + "#### 3c] Visualizing scores & prompts over trials" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pBYTLTwWqZH4" + }, + "source": [ + "Now, let's take a look at how this optimization looked over the course of each trial. We see that, in general, __performance increases overtime__, until it saturates after ~trial #13. Note that some of the 'pruned' trials have high scores, but were pruned early because they had comparitively lower scores on the easier slices of the data." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 333 + }, + "id": "rtMUNeicqZH4", + "outputId": "453b554f-4654-4184-d125-758288ddd6ee" + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "trial_logs = compiled_program.trial_logs\n", + "\n", + "# Extracting trial numbers, scores, and pruning status\n", + "trial_numbers = list(trial_logs.keys())\n", + "scores = [trial_logs[trial]['score'] for trial in trial_numbers]\n", + "pruning_status = [trial_logs[trial]['pruned'] for trial in trial_numbers]\n", + "\n", + "# Plot setup\n", + "plt.figure(figsize=(5, 3))\n", + "\n", + "# Plotting each point\n", + "for trial_number, score, pruned in zip(trial_numbers, scores, pruning_status):\n", + " if pruned:\n", + " plt.scatter(trial_number, score, color='grey', label='Pruned Trial' if 'Pruned Trial' not in plt.gca().get_legend_handles_labels()[1] else \"\")\n", + " else:\n", + " plt.scatter(trial_number, score, color='green', label='Successful Trial' if 'Successful Trial' not in plt.gca().get_legend_handles_labels()[1] else \"\")\n", + "\n", + "plt.xlabel('Trial Number')\n", + "plt.ylabel('Score')\n", + "plt.title('Trial Scores with Pruning Status')\n", + "plt.grid(True)\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5_Rwxfa1qZH4" + }, + "source": [ + "We can also __visualize the best prompts__ discovered by MIPRO as our trials progress... (though note that score increases are also due to the selected fewshot examples, which are not shown here for conciseness)." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "NnARfPRHqZH4", + "outputId": "9a9a9276-a56d-4f8d-c1d6-218d5d3d12f2" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Basline program | Score: 0:\n", + "Prompt 1 Instruction: Given the fields `context`, `question`, produce the fields `search_query`.\n", + "Prompt 2 Instruction: Given the fields `context`, `question`, produce the fields `answer`.\n", + "Prompt 3 Instruction: Given a question we are trying to answer and a list of passages, return a comma separated list of the numbers associated with each passage. These numbers should be ordered by helpfulness in answering the question, with most helpful passage number first, and the least helpful last.\n", + "\n", + "----------------\n", + "Best program after 0 trials | Score: 35.2:\n", + "Prompt 1 Instruction: Given the fields `context` and `question`, identify the specific information being asked for and produce a concise and accurate response.\n", + "Prompt 2 Instruction: Given a fact-based question related to pop culture, history, or entertainment, identify specific works or individuals and provide a concise answer directly corresponding to the question posed.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment, and a list of passages, rank the passages by their relevance to the question. Return a comma-separated list of the numbers associated with each passage, ordered from the most relevant (helpful) to the least relevant.\n", + "\n", + "Best program after 5 trials | Score: 35.6:\n", + "Prompt 1 Instruction: Given a fact-based question related to pop culture, history, or entertainment, with a focus on identifying specific works or individuals, generate a search query that includes the key elements of the question for precise information retrieval.\n", + "Prompt 2 Instruction: Given the information in the `context`, answer the `question` with a concise and specific response.\n", + "Prompt 3 Instruction: Given a question we are trying to answer and a list of passages, return a comma-separated list of the numbers associated with each passage, ordered by helpfulness in answering the question, with the most helpful passage number first and the least helpful last.\n", + "\n", + "Best program after 10 trials | Score: 38.2:\n", + "Prompt 1 Instruction: Given the varied syntax and focus on identifying specific works or individuals in fact-based questions related to pop culture, history, and entertainment, generate a search query that retrieves precise information relevant to the specific and varied questions posed.\n", + "Prompt 2 Instruction: Given a fact-based question related to pop culture, history, or entertainment and the corresponding context, provide a concise and accurate answer identifying specific works or individuals.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment, and a list of relevant passages, rank the passages by their relevance to the question. Return a comma-separated list of the numbers associated with each passage in order of relevance, with the most helpful passage number first, and the least helpful last.\n", + "\n", + "Best program after 15 trials | Score: 38.2:\n", + "Prompt 1 Instruction: Given the varied syntax and focus on identifying specific works or individuals in fact-based questions related to pop culture, history, and entertainment, generate a search query that retrieves precise information relevant to the specific and varied questions posed.\n", + "Prompt 2 Instruction: Given a fact-based question related to pop culture, history, or entertainment and the corresponding context, provide a concise and accurate answer identifying specific works or individuals.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment, and a list of relevant passages, rank the passages by their relevance to the question. Return a comma-separated list of the numbers associated with each passage in order of relevance, with the most helpful passage number first, and the least helpful last.\n", + "\n", + "Best program after 20 trials | Score: 41.6:\n", + "Prompt 1 Instruction: Given the fields `context` and `question`, determine the specific information being asked and compile a concise search query to retrieve the requested information.\n", + "Prompt 2 Instruction: Given a fact-based question related to pop culture, history, or entertainment, identify and provide the specific individual or work being referred to in the context.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment, and a list of passages, rank the passages in order of relevance to the question. Return a comma-separated list of the corresponding passage numbers, with the most relevant passage first and the least relevant last.\n", + "\n", + "Best program after 25 trials | Score: 41.6:\n", + "Prompt 1 Instruction: Given the fields `context` and `question`, determine the specific information being asked and compile a concise search query to retrieve the requested information.\n", + "Prompt 2 Instruction: Given a fact-based question related to pop culture, history, or entertainment, identify and provide the specific individual or work being referred to in the context.\n", + "Prompt 3 Instruction: Given a fact-based question related to pop culture, history, or entertainment, and a list of passages, rank the passages in order of relevance to the question. Return a comma-separated list of the corresponding passage numbers, with the most relevant passage first and the least relevant last.\n", + "\n" + ] + } + ], + "source": [ + "best_score = 0\n", + "\n", + "def get_signature(predictor):\n", + " if (hasattr(predictor, 'extended_signature')):\n", + " return predictor.extended_signature\n", + " elif (hasattr(predictor, 'signature')):\n", + " return predictor.signature\n", + "\n", + "print(f\"Basline program | Score: {best_score}:\")\n", + "for i,predictor in enumerate(program.predictors()):\n", + " print(f\"Prompt {i+1} Instruction: {get_signature(predictor).instructions}\")\n", + "print()\n", + "\n", + "print(\"----------------\")\n", + "\n", + "for trial_num in compiled_program.trial_logs:\n", + " program_score = compiled_program.trial_logs[trial_num][\"score\"]\n", + " program_pruned = compiled_program.trial_logs[trial_num][\"pruned\"]\n", + " if program_score > best_score and not program_pruned:\n", + " best_score = program_score\n", + " best_program_so_far = compiled_program.trial_logs[trial_num][\"program\"]\n", + " if trial_num % 5 == 0:\n", + " print(f\"Best program after {trial_num} trials | Score: {best_score}:\")\n", + " for i,predictor in enumerate(best_program_so_far.predictors()):\n", + " print(f\"Prompt {i+1} Instruction: {get_signature(predictor).instructions}\")\n", + " print()" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "dspy_test", + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From 26700f11145c0d1b04bd2dd1662c21313f29c1c1 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 10:53:32 -0800 Subject: [PATCH 20/79] notebook name change --- .../{hotpotqa_optimized.ipynb => hotpotqa_with_MIPRO.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/qa/hotpot/{hotpotqa_optimized.ipynb => hotpotqa_with_MIPRO.ipynb} (100%) diff --git a/examples/qa/hotpot/hotpotqa_optimized.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb similarity index 100% rename from examples/qa/hotpot/hotpotqa_optimized.ipynb rename to examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb From 76e0cb1bf829bf6bf2eb3be3d79b0a20e8d90e7f Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 11:15:30 -0800 Subject: [PATCH 21/79] minor changes to notebook+copro code (better print statements) --- dspy/teleprompt/copro_optimizer.py | 6 +++--- examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dspy/teleprompt/copro_optimizer.py b/dspy/teleprompt/copro_optimizer.py index 4cd7e3ba3..9d304cf9e 100644 --- a/dspy/teleprompt/copro_optimizer.py +++ b/dspy/teleprompt/copro_optimizer.py @@ -151,7 +151,7 @@ def compile(self, student, *, trainset, eval_kwargs): # For each iteration in depth... for d in range(self.depth): # TODO: fix this so that we eval the new batch of predictors with the new best followoing predictors - if self.verbose: print(f"Starting iteration {d}/{self.depth}.") + print(f"Iteration Depth: {d+1}/{self.depth}.") latest_scores = [] @@ -176,9 +176,9 @@ def compile(self, student, *, trainset, eval_kwargs): # Score the instruction / prefix if self.verbose: print("----------------") for i,predictor in enumerate(module_clone.predictors()): - if self.verbose: print(f"Predictor {i}") + if self.verbose: print(f"Predictor {i+1}") self._print_signature(predictor) - if self.verbose: print(f"At Depth {d}/{self.depth}, Evaluating Prompt Candidate #{c_i}/{len(candidates_)} for Predictor {p_i} of {len(module.predictors())}.") + print(f"At Depth {d+1}/{self.depth}, Evaluating Prompt Candidate #{c_i+1}/{len(candidates_)} for Predictor {p_i+1} of {len(module.predictors())}.") score = evaluate(module_clone, devset=trainset, **eval_kwargs) if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") total_calls += 1 diff --git a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb index e97102d97..3c1df4f37 100644 --- a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb +++ b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb @@ -15,7 +15,8 @@ "id": "3wEDck3ZqZH0" }, "source": [ - "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy" + "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy\n", + "" ] }, { @@ -136,7 +137,8 @@ " !pip install -e $repo_path\n", " !pip install --upgrade cloudpickle==3.0.0\n", "\n", - "import dspy" + "import dspy\n", + "import openai" ] }, { @@ -392,7 +394,7 @@ ], "source": [ "import cloudpickle as pickle\n", - "from dspy.teleprompt import BayesianSignatureOptimizer\n", + "from dspy.teleprompt import MIPRO\n", "\n", "LOAD_PRECOMPILED_PROGRAM = True\n", "\n", From f71416e90330e7139e679f22d63dbbb7378a34b1 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 19:22:36 +0000 Subject: [PATCH 22/79] Automatic Style fixes --- dspy/teleprompt/__init__.py | 12 ++++++------ dspy/teleprompt/mipro_optimizer.py | 12 +++++------- dspy/teleprompt/signature_opt.py | 5 +++-- dspy/teleprompt/signature_opt_bayesian.py | 7 ++++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dspy/teleprompt/__init__.py b/dspy/teleprompt/__init__.py index ba14c1b94..b8b922633 100644 --- a/dspy/teleprompt/__init__.py +++ b/dspy/teleprompt/__init__.py @@ -1,11 +1,11 @@ -from .teleprompt import * from .bootstrap import * -from .vanilla import * -from .random_search import * +from .copro_optimizer import COPRO from .finetune import * -from .teleprompt_optuna import * from .knn_fewshot import * +from .mipro_optimizer import MIPRO +from .random_search import * from .signature_opt import SignatureOptimizer from .signature_opt_bayesian import BayesianSignatureOptimizer -from .mipro_optimizer import MIPRO -from .copro_optimizer import COPRO \ No newline at end of file +from .teleprompt import * +from .teleprompt_optuna import * +from .vanilla import * diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index 2580e0945..eb2de8ed6 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -1,7 +1,8 @@ import math import random -from collections import defaultdict +import sys import textwrap +from collections import defaultdict import optuna @@ -12,9 +13,6 @@ from dspy.signatures.signature import signature_to_template from dspy.teleprompt import BootstrapFewShot from dspy.teleprompt.teleprompt import Teleprompter -import sys -import warnings - """ USAGE SUGGESTIONS: @@ -344,7 +342,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo for i in range(self.n): if i == 0: # Story empty set of demos as default for index 0 for module_p in module.predictors(): - if id(module_p) not in demo_candidates.keys(): + if id(module_p) not in demo_candidates: demo_candidates[id(module_p)] = [] demo_candidates[id(module_p)].append([]) else: @@ -359,7 +357,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo # Store the candidate demos for module_p, candidate_p in zip(module.predictors(), candidate_program.predictors()): - if id(module_p) not in demo_candidates.keys(): + if id(module_p) not in demo_candidates: demo_candidates[id(module_p)] = [] demo_candidates[id(module_p)].append(candidate_p.demos) @@ -442,7 +440,7 @@ def objective(trial): # Handle pruning based on the intermediate value. if trial.should_prune(): - print(f"Trial pruned.") + print("Trial pruned.") trial_logs[trial_num]["score"] = curr_weighted_avg_score trial_logs[trial_num]["pruned"] = True trial_num += 1 diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index ea4bfa61c..e3cc931e0 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -1,5 +1,6 @@ + from .copro_optimizer import COPRO -import warnings + """ =============================================================== DEPRECATED!!! @@ -38,7 +39,7 @@ def __init__(self, prompt_model=None, metric=None, breadth=10, depth=3, init_tem # "Use `COPRO` instead.", # DeprecationWarning # ) - print(u"\u001b[31m[WARNING] SignatureOptimizer has been deprecated and replaced with COPRO. SignatureOptimizer will be removed in a future release. \u001b[31m") + print("\u001b[31m[WARNING] SignatureOptimizer has been deprecated and replaced with COPRO. SignatureOptimizer will be removed in a future release. \u001b[31m") super().__init__(prompt_model, metric, breadth, depth, init_temperature, verbose, track_stats) def compile(self, student, *, devset, eval_kwargs): diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index e1caef71d..995378cf1 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -1,6 +1,7 @@ -from dspy.teleprompt.mipro_optimizer import MIPRO import warnings +from dspy.teleprompt.mipro_optimizer import MIPRO + """ =============================================================== DEPRECATED!!! @@ -42,7 +43,7 @@ def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10 # "Use `MIPRO` instead.", # DeprecationWarning # ) - print(u"\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") + print("\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) @@ -63,7 +64,7 @@ def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, warnings.warn( "`optuna_trials_num` is deprecated and will be removed in a future version. " "Use `trials_num` instead.", - DeprecationWarning + DeprecationWarning, ) # Use trials_num as a fallback if trials_num is not provided if trials_num is None: From fc664d5e339d2c16b3b537bdbb13d9707e6fd9c4 Mon Sep 17 00:00:00 2001 From: Isaac Miller <17116851+isaacbmiller@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:24:56 -0600 Subject: [PATCH 23/79] ci(dspy): Add main push test run back (#600) * Add main push action back and fix comment bot * Try to fix comment bot * Remove comment bot workflow - to be added later --- .github/workflows/pr_comment.yml | 37 -------------------------------- .github/workflows/run_tests.yml | 21 +++--------------- 2 files changed, 3 insertions(+), 55 deletions(-) delete mode 100644 .github/workflows/pr_comment.yml diff --git a/.github/workflows/pr_comment.yml b/.github/workflows/pr_comment.yml deleted file mode 100644 index 87afb5094..000000000 --- a/.github/workflows/pr_comment.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Comment for PR - -on: - workflow_run: - workflows: ["Check for Ruff Fix, Test, and Build"] - types: - - completed - -jobs: - comment: - runs-on: ubuntu-latest - steps: - - name: "Download Ruff Fix Outcome Artifact" - uses: actions/download-artifact@v2 - with: - name: ruff-fix-outcome - path: artifacts - - - name: "Read Ruff Fix Outcome" - id: ruff_outcome - run: | - outcome=$(cat artifacts/ruff_fix_outcome.txt) - echo "RUFF_FIX_OUTCOME=$outcome" >> $GITHUB_ENV - - - name: "Comment on PR if Ruff Fix Failed" - if: env.RUFF_FIX_OUTCOME == 'true' - uses: actions/github-script@v5 - with: - script: | - const pr_number = ${{ github.event.workflow_run.pull_requests[0].number }}; - const message = 'It seems like there are issues with the formatting. Please run `ruff check . --fix-only` and commit to address these issues.'; - github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr_number, - body: message - }); diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index e57c6ff0f..96e81e381 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -1,6 +1,9 @@ name: Lint, Test, and Build on: + push: + branches: + - main pull_request: types: [opened, synchronize, reopened] @@ -24,21 +27,6 @@ jobs: args: --fix-only --exit-non-zero-on-fix continue-on-error: true - - name: Determine Ruff Fix Outcome - run: | - if [ ${{ steps.ruff_fix.outcome }} == 'failure' ]; then - echo "RUFF_FAILED=true" >> $GITHUB_ENV - echo ${{ steps.ruff_fix.outcome }} > ruff_fix_outcome.txt - else - echo "RUFF_FAILED=false" >> $GITHUB_ENV - echo ${{ steps.ruff_fix.outcome }} > ruff_fix_outcome.txt - fi - - - uses: actions/upload-artifact@v2 - with: - name: ruff-fix-outcome - path: ruff_fix_outcome.txt - - name: Fail Workflow if Ruff Fix Failed if: steps.ruff_fix.outcome == 'failure' run: | @@ -52,7 +40,6 @@ jobs: strategy: matrix: python-version: ["3.9"] - if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - name: Load cached Poetry installation @@ -84,7 +71,6 @@ jobs: strategy: matrix: python-version: ["3.9"] - if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - name: Load cached Poetry installation @@ -116,7 +102,6 @@ jobs: strategy: matrix: python-version: ["3.9"] - if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - name: Load cached Poetry installation From a4f7ca623037e22117966e2d88fc700cb6354371 Mon Sep 17 00:00:00 2001 From: swairshah Date: Thu, 7 Mar 2024 14:29:02 -0800 Subject: [PATCH 24/79] Fix code issues in signature-optimizer.mdx 1. use the HotPotQA dataset instead of gsm8k 2. result.rationale instead of result.reason 3. process devset to include input_keys --- .../deep-dive/teleprompter/signature-optimizer.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/docs/deep-dive/teleprompter/signature-optimizer.mdx b/docs/docs/deep-dive/teleprompter/signature-optimizer.mdx index 25624e60a..740aa2a4a 100644 --- a/docs/docs/deep-dive/teleprompter/signature-optimizer.mdx +++ b/docs/docs/deep-dive/teleprompter/signature-optimizer.mdx @@ -26,7 +26,7 @@ from dspy.datasets import HotPotQA dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0) -trainset, devset = gms8k.train, gms8k.dev +trainset, devset = dataset.train, dataset.dev ``` We'll now define a class based signature for QA task similar to `question->answer` and pass it to `ChainOfThought` module, that will give us the result via Chain Of Thought from the LM client for this signature. @@ -49,7 +49,7 @@ class CoTPipeline(dspy.Module): result = self.predictor(question=question) return dspy.Prediction( answer=result.answer, - reasoning=result.reasoning, + reasoning=result.rationale, ) ``` @@ -62,6 +62,7 @@ def validate_context_and_answer(example, pred, trace=None): answer_EM = dspy.evaluate.answer_exact_match(example, pred) return answer_EM +NUM_THREADS = 5 evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=NUM_THREADS, display_progress=True, display_table=False) ``` @@ -70,7 +71,8 @@ To evaluate the `CoTPipeline` we'll need to create an object of it and pass it a ```python cot_baseline = CoTPipeline() -evaluate(cot_baseline, devset=devset[:]) +devset_with_input = [dspy.Example({"question": r["question"], "answer": r["answer"]}).with_inputs("question") for r in devset] +evaluate(cot_baseline, devset=devset_with_input) ``` Now we have the baseline pipeline ready to use, so let's try using the `SignatureOptimizer` teleprompter and optimizing our pipeline to make it even better! @@ -162,4 +164,4 @@ This iterative approach allows for continuous refinement of instructions and pre *** - \ No newline at end of file + From f44e50e4e4b729efbef2e4ce678b9220321356a0 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 14:50:37 -0800 Subject: [PATCH 25/79] a few optimizer updates --- dspy/teleprompt/mipro_optimizer.py | 18 +- dspy/teleprompt/signature_opt.py | 5 - dspy/teleprompt/signature_opt_bayesian.py | 30 +- examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb | 3950 +++++++++++++++++- 4 files changed, 3935 insertions(+), 68 deletions(-) diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index 2580e0945..18449de6c 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -19,13 +19,13 @@ """ USAGE SUGGESTIONS: -The following code can be used to compile a optimized signature teleprompter using the MIPROOptimizer, and evaluate it on an end task: +The following code can be used to compile a optimized signature teleprompter using the MIPRO, and evaluate it on an end task: -from dspy.teleprompt import MIPROOptimizer +from dspy.teleprompt import MIPRO -teleprompter = MIPROOptimizer(prompt_model=prompt_model, task_model=task_model, metric=metric, num_candidates=10, init_temperature=1.0) +teleprompter = MIPRO(prompt_model=prompt_model, task_model=task_model, metric=metric, num_candidates=10, init_temperature=1.0) kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=0) -compiled_prompt_opt = teleprompter.compile(program, trainset=trainset[:TRAIN_NUM], trials_num=100, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs=kwargs) +compiled_prompt_opt = teleprompter.compile(program, trainset=trainset[:TRAIN_NUM], num_trials=100, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs=kwargs) eval_score = evaluate(compiled_prompt_opt, devset=evalset[:EVAL_NUM], **kwargs) Note that this teleprompter takes in the following parameters: @@ -279,7 +279,7 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo return candidates, evaluated_candidates - def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, trials_num=None): + def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, num_trials=None): # Define ANSI escape codes for colors YELLOW = '\033[93m' BLUE = '\033[94m' @@ -288,7 +288,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo random.seed(seed) - estimated_task_model_calls_wo_module_calls = len(trainset) * trials_num # M * T * P + estimated_task_model_calls_wo_module_calls = len(trainset) * num_trials # M * T * P estimated_prompt_model_calls = 10 + self.n * len(student.predictors()) # num data summary calls + N * P user_message = textwrap.dedent(f"""\ @@ -296,7 +296,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo Please be advised that based on the parameters you have set, the maximum number of LM calls is projected as follows: - {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{trials_num}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} + {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{num_trials}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.n}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} {YELLOW}{BOLD}Estimated Cost Calculation:{ENDC} @@ -307,7 +307,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo For a preliminary estimate of potential costs, we recommend you perform your own calculations based on the task and prompt models you intend to use. If the projected costs exceed your budget or expectations, you may consider: - {YELLOW}- Reducing the number of trials (`trials_num`), the size of the trainset, or the number of LM calls in your program.{ENDC} + {YELLOW}- Reducing the number of trials (`num_trials`), the size of the trainset, or the number of LM calls in your program.{ENDC} {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC} To proceed with the execution of this program, please confirm by typing {BLUE}'y'{ENDC} for yes or {BLUE}'n'{ENDC} for no. @@ -471,7 +471,7 @@ def objective(trial): objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, trainset) sampler = optuna.samplers.TPESampler(seed=seed) study = optuna.create_study(direction="maximize", sampler=sampler) - score = study.optimize(objective_function, n_trials=trials_num) + score = study.optimize(objective_function, n_trials=num_trials) if best_program is not None and self.track_stats: best_program.trial_logs = trial_logs diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index ea4bfa61c..a051eb496 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -33,11 +33,6 @@ class SignatureOptimizer(COPRO): def __init__(self, prompt_model=None, metric=None, breadth=10, depth=3, init_temperature=1.4, verbose=False, track_stats=False): - # warnings.warn( - # "`SignatureOptimizer` is deprecated and will be removed in a future version. " - # "Use `COPRO` instead.", - # DeprecationWarning - # ) print(u"\u001b[31m[WARNING] SignatureOptimizer has been deprecated and replaced with COPRO. SignatureOptimizer will be removed in a future release. \u001b[31m") super().__init__(prompt_model, metric, breadth, depth, init_temperature, verbose, track_stats) diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index e1caef71d..48b007671 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -37,35 +37,9 @@ class BayesianSignatureOptimizer(MIPRO): def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): - # warnings.warn( - # "`BayesianSignatureOptimizer` is deprecated and will be removed in a future version. " - # "Use `MIPRO` instead.", - # DeprecationWarning - # ) print(u"\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) - def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, trials_num=None, optuna_trials_num=None): - # Define ANSI escape codes for colors - YELLOW = '\033[93m' - BLUE = '\033[94m' - BOLD = '\033[1m' - ENDC = '\033[0m' # Resets the color to default - - # Check if both trials_num and optuna_trials_num are None - if trials_num is None and optuna_trials_num is None: - raise ValueError(f"{YELLOW}{BOLD}You must specify the number of trials using the 'trials_num' parameter.{ENDC}") - - # Check if the deprecated parameter is used - if optuna_trials_num is not None: - # Issue a deprecation warning - warnings.warn( - "`optuna_trials_num` is deprecated and will be removed in a future version. " - "Use `trials_num` instead.", - DeprecationWarning - ) - # Use trials_num as a fallback if trials_num is not provided - if trials_num is None: - trials_num = optuna_trials_num - return super().compile(student, trainset=devset, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, eval_kwargs=eval_kwargs, seed=seed, view_data=view_data, view_examples=view_examples, requires_permission_to_run=requires_permission_to_run, num_trials=trials_num) \ No newline at end of file + def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, optuna_trials_num, view_data=True, view_examples=True, requires_permission_to_run=True, num_trials=None): + return super().compile(student, trainset=devset, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, eval_kwargs=eval_kwargs, seed=seed, view_data=view_data, view_examples=view_examples, requires_permission_to_run=requires_permission_to_run, num_trials=optuna_trials_num) \ No newline at end of file diff --git a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb index 3c1df4f37..cb450d763 100644 --- a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb +++ b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb @@ -15,8 +15,7 @@ "id": "3wEDck3ZqZH0" }, "source": [ - "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy\n", - "" + "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy" ] }, { @@ -70,10 +69,35 @@ "execution_count": 1, "metadata": { "colab": { - "base_uri": "https://localhost:8080/" + "base_uri": "https://localhost:8080/", + "height": 205, + "referenced_widgets": [ + "827d6f08a1894525937562b64df50dc6", + "c977f3fcb63349b294414c28e6bb17d3", + "9f2a85011d284134bced1a72e0f13d9c", + "435b0b18054e454eac41b3722cbe0400", + "b563cc49cf3341f8a54ab0183e8a9794", + "b2c1beb7364a43288209f5e5a6ad2514", + "e338d68fb7694b85bc573c0df83fa23e", + "6fcb23a0eb444b88a1cef94740551fe8", + "35a4261bb9494f068b4e5f2cbe9a927a", + "0cb7129e44b04ef88154a8a32b025391", + "63b53c83345841b69b06b71b830e9adf", + "aa4f1d66d377449c8cb4a73056138d50", + "54f904d1274c499ca7e714fa8cdf6d61", + "2efe34e3d66b4b64b4552d278d4a5962", + "a9c39bc2e1804ad399f1dc66d192df46", + "d04e9ed9ccb64b17903e10e749d097a7", + "abec858558814b2b809cd318aaac1545", + "ce54414ed74441478f593ae366ff16b4", + "fcd8aef3637c4449bef71809764642c2", + "e716458e84c14cb7948ab6dc61f337b9", + "4c081aaabbdb448b91fead4fa73f6c0b", + "da0f46c68b0141a48c887faa0843d5ab" + ] }, "id": "l4Fsh7EhqZH1", - "outputId": "bc43f9ad-e090-4e5d-bd54-1e998225b44d" + "outputId": "5fea0db6-8cb1-4485-91f7-bc1e7dfe5d4b" }, "outputs": [], "source": [ @@ -106,7 +130,7 @@ "base_uri": "https://localhost:8080/" }, "id": "JpijP_d7qZH2", - "outputId": "daf24b9e-7030-4bf1-a08f-ff8b4ad42e22" + "outputId": "422dc4d0-4574-4e4b-935a-c7b4c875472f" }, "outputs": [], "source": [ @@ -137,8 +161,7 @@ " !pip install -e $repo_path\n", " !pip install --upgrade cloudpickle==3.0.0\n", "\n", - "import dspy\n", - "import openai" + "import dspy" ] }, { @@ -198,10 +221,112 @@ "execution_count": 4, "metadata": { "colab": { - "base_uri": "https://localhost:8080/" + "base_uri": "https://localhost:8080/", + "height": 340, + "referenced_widgets": [ + "fb0bb0cd51d24f7a9ea4bc5acdab0b6f", + "4cd600dc92fa4dcbb1f6878dfc951a84", + "2d9675dfff7244e3a2c4273e6beac742", + "ebb8d03b2088443988427c674f2ebd08", + "bb649fd497164542865182285391c1cb", + "0ce5aafe3feb4e30b154e8feee246680", + "292a903dd61540beb28f0dcc33e60173", + "4c10718ba99243a795348fffc0317d89", + "47ba7929b5a3483bad6dba45b3839d28", + "d50c0b7e0f35439c938bee5d2159ff82", + "c8da2fa4b14e43948824f527e9665354", + "02b66439b0d3463c835f54ee43a81b29", + "757ec3ba99bc49b78386be420b315738", + "14f1e99c941349ceabc1d360deb1a14d", + "d601031bf4744c849885f7becf1e5f76", + "2ac62fd2e5d64e44a69551d27913caf8", + "a6a9ecf3b2d74a1ab78a904f76b462c7", + "0fcf2dc801ac414ca7ff9db0790e322c", + "b2b11f62717f482a8c7d28dfef7282e0", + "ffda68bae3e34d39abce4d2064b88617", + "0083f3cd53b742a6916f9131bffc92ab", + "85c4f1c241054d989d893130ca7ec595", + "ef2f0db8dc4148daae63001d4c6a555b", + "2f24b6572cb44cbaac147b28a4490582", + "83926bd6a50441959fdc945808cbea61", + "a93f7fced2444026bed86ff3ac73ab46", + "b7d6568fa80446e1a9ca2f9102b47f7f", + "f66e4271b9544b83b598700cc97593e9", + "530d6c38c848425082f506709fecb5f7", + "e035507b6408448f87ca0fee35bc1bb1", + "42d3de61644547ad80e585629fd97c3d", + "978d5cab723f4f02bcadb71b099840a8", + "05f74ff1c66d41858e4436707089ce10", + "67dd858331754b7a944bd9cb725c5409", + "9b318e36701f43a38bf49db28f1f82d6", + "5859289715b94e09b45bb2215fd8f663", + "4ffa164e576e43788118a2574ae6089b", + "c066cdb020ff4d0f925def7eb9373228", + "48b4d8350a074defb044eeaa9586f9c0", + "b8924c8accbc415e8e28bc232d063003", + "a2b761c3ce72458a8ef3d47903d42828", + "6bd216ee356e4853ac52c81f5632834d", + "053a5c1ad4cd47548a8a358dc8834c50", + "338ffb9834b44e0b9a9a353ede75f9d6", + "3ec77a173a5345fcb06827a87b4ddf38", + "c47e844caea446e1a452426ed899fe36", + "060cbe0e37dc422591916d3768066224", + "e68714c12f8543c9b14360f8f1d37604", + "bfdbc53eb3d34077bbfa0f8806733704", + "7038244ae993489eb76422d4f6135e58", + "76a9b3ae6fdb4ee2a228966556287752", + "13ee127ea31847b9b3d5f6a8a0b10cfa", + "f99a2f9616c744578b88fb1322674c32", + "43d07caba731495f9fe22a7ef81ef19a", + "2532bb223c2d4dbeb2cfeffbfdeac65b", + "cd15509869ed4a518b6d4d48b932e314", + "2ab35b29510c422ca4f07bfad4339419", + "bba71ee322f548439853954f1c055977", + "cb6ef0a279774d1f81cf2f4efb3b3c04", + "eca4539630b04bb2b927d780ef4ca849", + "bdd29de7feba4156823b10124217ef54", + "63742b8642ae4a94999bd5cdb3fa7da2", + "6aec8a01051743acab8de920672cf38f", + "0576fd9cffb4489fa07c4af347ada10e", + "e8e84a2a7343409d8f81439a42e53601", + "f13ff2cfe1a6443296cd1a9fe956312e", + "371665875b63442586198c64f3f441dc", + "4dc0cc26e04741c1b9a28deb1c0f533d", + "c95c3c713b9c4e7b95ab273b17c20788", + "176abb1c80904828965774b9c5ed2558", + "10cf746afb1b4c748ce5fda0dd026ab9", + "67d3a00c8e9e4e9a81a039e8b05c1200", + "b27566e9133a493bbba2af2f1cd1118c", + "ebb50f6701c146efafef65ab75cb5901", + "8dbde39ea3c144268b2547c55863c929", + "70c258c2634b431cb283420f86675818", + "88f9b45c9508415fb29fe786768be085", + "1f5f6e14543a4fe48f90459afe074739", + "823a30d9f3f34793b8eb8b79899eaf19", + "bb56dc209d8646ec84b3d194761c1e57", + "30d9db28931442a0b15ef29792e0a6a9", + "cbe4ee8e8d5646b98f4ff470952384da", + "52747a49054d454e8f899fc832985877", + "1af61e78281347429396163cdae419ed", + "f30e71e4d77c43d7b8b45ff9b3905d51", + "90a8e892d747436aa02bce59454b117d", + "ad62117365344dfbbed1fd46ae8238e6", + "a2454d2f78b34a279e8cad724200d5eb", + "ae83b2e7628e4345896eba886b563bc3", + "560375a7cc364b65be6f72db30139ce3", + "8c0bf6da280e4db88b24b2e1028f9841", + "44ed3f5af4234059b806dcc26abb99c7", + "dd09c11a454b4edb81f18e018dc917ca", + "56ac79bb987146c7ba76f1bd0315360f", + "e2e51fbcedad401ba7d79ac45258a3df", + "97e73f6600c641fd9e724d992a8b8d6d", + "68d13e7ab60245f9910806508ae08cc0", + "571bcef58c3440ce9aa9cb4f441ec97a", + "d2f1105f250542649c0b6cb4c27d75df" + ] }, "id": "hiVgd3N7qZH3", - "outputId": "09e1ea66-7c8d-438a-8c37-1ab96fe8cdf0" + "outputId": "8b0ef2cf-1836-4aab-8990-62aa6240ab1f" }, "outputs": [ { @@ -300,14 +425,21 @@ "base_uri": "https://localhost:8080/" }, "id": "MU2aHQBTqZH3", - "outputId": "fd60fbb3-ca89-4ecb-911b-24751f220cc6" + "outputId": "32f26cb9-2e6d-48b7-9732-9f3c5b60ef7a" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 108 / 500 (21.6): 100%|██████████| 500/500 [00:33<00:00, 14.90it/s]\n", + " 0%| | 0/500 [00:00 Date: Thu, 7 Mar 2024 14:56:33 -0800 Subject: [PATCH 26/79] adding in an import that was accidentally removed --- dspy/teleprompt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dspy/teleprompt/__init__.py b/dspy/teleprompt/__init__.py index b8b922633..39462634d 100644 --- a/dspy/teleprompt/__init__.py +++ b/dspy/teleprompt/__init__.py @@ -1,5 +1,6 @@ from .bootstrap import * from .copro_optimizer import COPRO +from .ensemble import * from .finetune import * from .knn_fewshot import * from .mipro_optimizer import MIPRO From d7bf3bcff5102f328dc4105d15dbedabf2c974dd Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 15:00:19 -0800 Subject: [PATCH 27/79] updating mipro tests --- .../teleprompt/test_signature_opt_bayesian.py | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/teleprompt/test_signature_opt_bayesian.py b/tests/teleprompt/test_signature_opt_bayesian.py index 0cf655784..38f560da4 100644 --- a/tests/teleprompt/test_signature_opt_bayesian.py +++ b/tests/teleprompt/test_signature_opt_bayesian.py @@ -3,7 +3,7 @@ import re import dspy from dsp.modules import LM -from dspy.teleprompt.signature_opt_bayesian import BayesianSignatureOptimizer +from dspy.teleprompt.signature_opt_bayesian import MIPRO from dspy.utils.dummies import DummyLM from dspy import Example @@ -41,7 +41,7 @@ class ConditionalLM(LM): def __init__(self): super().__init__("conditional-lm") - def basic_request(self, prompt, n=1, **kwargs): + def basic_request(self, prompt, num_candidates=1, **kwargs): # If we are in the "optimization" stage, we don't say much. if prompt.endswith("Observations:"): answer = " (*silence*)" @@ -113,8 +113,8 @@ def get_convo(self, index): def test_bayesian_signature_optimizer_initialization(): - optimizer = BayesianSignatureOptimizer( - metric=simple_metric, n=10, init_temperature=1.4, verbose=True, track_stats=True + optimizer = MIPRO( + metric=simple_metric, num_candidates=10, init_temperature=1.4, verbose=True, track_stats=True ) assert optimizer.metric == simple_metric, "Metric not correctly initialized" assert optimizer.n == 10, "Incorrect 'n' parameter initialization" @@ -141,9 +141,9 @@ def test_signature_optimizer_optimization_process(): student = SimpleModule(signature="input -> output") - optimizer = BayesianSignatureOptimizer( + optimizer = MIPRO( metric=simple_metric, - n=10, + num_candidates=10, init_temperature=1.4, verbose=False, track_stats=False, @@ -152,11 +152,12 @@ def test_signature_optimizer_optimization_process(): # Adjustments: Include required parameters for the compile method optimized_student = optimizer.compile( student=student, - devset=trainset, - optuna_trials_num=10, + trainset=trainset, + num_trials=10, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs={"num_threads": 1, "display_progress": False}, + requires_permission_to_run=False, ) assert len(optimized_student.predictor.demos) == 5 @@ -167,9 +168,9 @@ def test_signature_optimizer_bad_lm(): lm=DummyLM([f"Optimized instruction {i}" for i in range(30)]) ) student = SimpleModule(signature="input -> output") - optimizer = BayesianSignatureOptimizer( + optimizer = MIPRO( metric=simple_metric, - n=10, + num_candidates=10, init_temperature=1.4, verbose=False, track_stats=False, @@ -181,11 +182,12 @@ def test_signature_optimizer_bad_lm(): with pytest.raises(ValueError): _optimized_student = optimizer.compile( student=student, - devset=trainset, - optuna_trials_num=10, + trainset=trainset, + num_trials=10, max_bootstrapped_demos=3, max_labeled_demos=5, eval_kwargs={"num_threads": 1, "display_progress": False}, + requires_permission_to_run=False, ) @@ -195,9 +197,9 @@ def test_optimization_and_output_verification(): lm = ConditionalLM() dspy.settings.configure(lm=lm) - optimizer = BayesianSignatureOptimizer( + optimizer = MIPRO( metric=simple_metric, - n=10, + num_candidates=10, init_temperature=1.4, verbose=False, track_stats=True, @@ -208,11 +210,12 @@ def test_optimization_and_output_verification(): # Compile the student with the optimizer optimized_student = optimizer.compile( student=student, - devset=trainset, - optuna_trials_num=4, + trainset=trainset, + num_trials=4, max_bootstrapped_demos=2, max_labeled_demos=3, eval_kwargs={"num_threads": 1, "display_progress": False}, + requires_permission_to_run=False, ) # Simulate calling the optimized student with a new input From 2704f5af1a42f75270d6a9a7692d0f1f0857c770 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 15:03:40 -0800 Subject: [PATCH 28/79] fixing warning statement --- dspy/teleprompt/mipro_optimizer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index f54c2822e..fce5377fb 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -306,8 +306,9 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo and prompt models you intend to use. If the projected costs exceed your budget or expectations, you may consider: {YELLOW}- Reducing the number of trials (`num_trials`), the size of the trainset, or the number of LM calls in your program.{ENDC} - {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC} - + {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC}""") + + user_confirmation_message = textwrap.dedent(f"""\ To proceed with the execution of this program, please confirm by typing {BLUE}'y'{ENDC} for yes or {BLUE}'n'{ENDC} for no. If you would like to bypass this confirmation step in future executions, set the {YELLOW}`requires_permission_to_run`{ENDC} flag to {YELLOW}`False`.{ENDC} @@ -321,6 +322,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo if requires_permission_to_run: + print(user_confirmation_message) user_input = input("Do you wish to continue? (y/n): ").strip().lower() if user_input != 'y': print("Compilation aborted by the user.") From 484da6aab6da9940fe8c5d0cac0870735eb66565 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 15:07:55 -0800 Subject: [PATCH 29/79] fixing bug when requires_permission_to_run=False, and doing ruff cleanups --- dspy/teleprompt/mipro_optimizer.py | 265 +++++++++++----------- dspy/teleprompt/signature_opt.py | 2 +- dspy/teleprompt/signature_opt_bayesian.py | 3 +- 3 files changed, 135 insertions(+), 135 deletions(-) diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index fce5377fb..3612b0962 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -117,8 +117,6 @@ def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, num_ def _print_full_program(self, program): for i,predictor in enumerate(program.predictors()): if self.verbose: print(f"Predictor {i}") - # if self.verbose: print(f"i: {self._get_signature(predictor).instructions}") - # if self.verbose: print(f"p: {self._get_signature(predictor).fields[-1].name}") if self.verbose: print(f"i: {self._get_signature(predictor).instructions}") *_, last_field = self._get_signature(predictor).fields.values() if self.verbose: print(f"p: {last_field.json_schema_extra['prefix']}") @@ -321,160 +319,163 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo sys.stdout.flush() # Flush the output buffer to force the message to print + run=True if requires_permission_to_run: print(user_confirmation_message) user_input = input("Do you wish to continue? (y/n): ").strip().lower() if user_input != 'y': print("Compilation aborted by the user.") + run=False + + if run: + # Set up program and evaluation function + module = student.deepcopy() + evaluate = Evaluate(devset=trainset, metric=self.metric, **eval_kwargs) + + # In the case where the bootstrapped and labeled demos are set to 0, we'll stil bootstrap examples to use in our meta prompt + if max_bootstrapped_demos==0 and max_labeled_demos==0: #TODO: address case when max_bootstrapped alone is 0 + max_bootstrapped_demos_for_candidate_gen = 1 + max_labeled_demos_for_candidate_gen = 1 #TODO: this might only need to be 0 else: - # Set up program and evaluation function - module = student.deepcopy() - evaluate = Evaluate(devset=trainset, metric=self.metric, **eval_kwargs) - - # In the case where the bootstrapped and labeled demos are set to 0, we'll stil bootstrap examples to use in our meta prompt - if max_bootstrapped_demos==0 and max_labeled_demos==0: #TODO: address case when max_bootstrapped alone is 0 - max_bootstrapped_demos_for_candidate_gen = 1 - max_labeled_demos_for_candidate_gen = 1 #TODO: this might only need to be 0 + max_bootstrapped_demos_for_candidate_gen = max_bootstrapped_demos + max_labeled_demos_for_candidate_gen = max_labeled_demos + + # Generate N few shot example sets + demo_candidates = {} + for i in range(self.n): + if i == 0: # Story empty set of demos as default for index 0 + for module_p in module.predictors(): + if id(module_p) not in demo_candidates: + demo_candidates[id(module_p)] = [] + demo_candidates[id(module_p)].append([]) else: - max_bootstrapped_demos_for_candidate_gen = max_bootstrapped_demos - max_labeled_demos_for_candidate_gen = max_labeled_demos - - # Generate N few shot example sets - demo_candidates = {} - for i in range(self.n): - if i == 0: # Story empty set of demos as default for index 0 - for module_p in module.predictors(): - if id(module_p) not in demo_candidates: - demo_candidates[id(module_p)] = [] - demo_candidates[id(module_p)].append([]) - else: - if self.verbose: print(f"Creating basic bootstrap: {i}/{self.n-1}") - - # Create a new basic bootstrap few - shot program . - rng = random.Random(i) - shuffled_trainset = trainset[:] # Create a copy of devset - rng.shuffle(shuffled_trainset) # Shuffle the copy - tp = BootstrapFewShot(metric = self.metric, max_bootstrapped_demos=max_bootstrapped_demos_for_candidate_gen, max_labeled_demos=max_labeled_demos_for_candidate_gen, teacher_settings=self.teacher_settings) - candidate_program = tp.compile(student=module.deepcopy(), trainset=shuffled_trainset) - - # Store the candidate demos - for module_p, candidate_p in zip(module.predictors(), candidate_program.predictors()): - if id(module_p) not in demo_candidates: - demo_candidates[id(module_p)] = [] - demo_candidates[id(module_p)].append(candidate_p.demos) - - # Generate N candidate prompts - instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, trainset) + if self.verbose: print(f"Creating basic bootstrap: {i}/{self.n-1}") + + # Create a new basic bootstrap few - shot program . + rng = random.Random(i) + shuffled_trainset = trainset[:] # Create a copy of devset + rng.shuffle(shuffled_trainset) # Shuffle the copy + tp = BootstrapFewShot(metric = self.metric, max_bootstrapped_demos=max_bootstrapped_demos_for_candidate_gen, max_labeled_demos=max_labeled_demos_for_candidate_gen, teacher_settings=self.teacher_settings) + candidate_program = tp.compile(student=module.deepcopy(), trainset=shuffled_trainset) + + # Store the candidate demos + for module_p, candidate_p in zip(module.predictors(), candidate_program.predictors()): + if id(module_p) not in demo_candidates: + demo_candidates[id(module_p)] = [] + demo_candidates[id(module_p)].append(candidate_p.demos) + + # Generate N candidate prompts + instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, trainset) - # Reset demo_candidates to None for our optimization if the user asked for no fewshot examples - if max_bootstrapped_demos==0 and max_labeled_demos==0: - demo_candidates = None + # Reset demo_candidates to None for our optimization if the user asked for no fewshot examples + if max_bootstrapped_demos==0 and max_labeled_demos==0: + demo_candidates = None - # Initialize variables to store the best program and its score - best_score = float('-inf') - best_program = None - trial_num = 0 + # Initialize variables to store the best program and its score + best_score = float('-inf') + best_program = None + trial_num = 0 - trial_logs = {} + trial_logs = {} - # Define our trial objective - def create_objective(baseline_program, instruction_candidates, demo_candidates, evaluate, trainset): - def objective(trial): - nonlocal best_program, best_score, trial_num, trial_logs # Allow access to the outer variables - candidate_program = baseline_program.deepcopy() + # Define our trial objective + def create_objective(baseline_program, instruction_candidates, demo_candidates, evaluate, trainset): + def objective(trial): + nonlocal best_program, best_score, trial_num, trial_logs # Allow access to the outer variables + candidate_program = baseline_program.deepcopy() - # Suggest the instruction to use for our predictor - print(f"Starting trial #{trial_num}") - trial_logs[trial_num] = {} + # Suggest the instruction to use for our predictor + print(f"Starting trial #{trial_num}") + trial_logs[trial_num] = {} - for p_old, p_new in zip(baseline_program.predictors(), candidate_program.predictors()): + for p_old, p_new in zip(baseline_program.predictors(), candidate_program.predictors()): - # Get instruction candidates for our given predictor - p_instruction_candidates = instruction_candidates[id(p_old)] - if demo_candidates: p_demo_candidates = demo_candidates[id(p_old)] + # Get instruction candidates for our given predictor + p_instruction_candidates = instruction_candidates[id(p_old)] + if demo_candidates: p_demo_candidates = demo_candidates[id(p_old)] - # Suggest the index of the instruction candidate to use in our trial - instruction_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_instruction",range(len(p_instruction_candidates))) - if demo_candidates: demos_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_demos",range(len(p_demo_candidates))) - trial_logs[trial_num][f"{id(p_old)}_predictor_instruction"] = instruction_idx - if demo_candidates: trial_logs[trial_num][f"{id(p_old)}_predictor_demos"] = demos_idx + # Suggest the index of the instruction candidate to use in our trial + instruction_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_instruction",range(len(p_instruction_candidates))) + if demo_candidates: demos_idx = trial.suggest_categorical(f"{id(p_old)}_predictor_demos",range(len(p_demo_candidates))) + trial_logs[trial_num][f"{id(p_old)}_predictor_instruction"] = instruction_idx + if demo_candidates: trial_logs[trial_num][f"{id(p_old)}_predictor_demos"] = demos_idx - # Get the selected instruction candidate - selected_candidate = p_instruction_candidates[instruction_idx] - selected_instruction = selected_candidate.proposed_instruction.strip('"').strip() - selected_prefix = selected_candidate.proposed_prefix_for_output_field.strip('"').strip() + # Get the selected instruction candidate + selected_candidate = p_instruction_candidates[instruction_idx] + selected_instruction = selected_candidate.proposed_instruction.strip('"').strip() + selected_prefix = selected_candidate.proposed_prefix_for_output_field.strip('"').strip() - # Use this candidates in our program - *_, last_field = self._get_signature(p_new).fields.keys() - updated_signature = self._get_signature(p_new).with_instructions(selected_instruction).with_updated_fields(last_field, prefix=selected_prefix) - self._set_signature(p_new, updated_signature) + # Use this candidates in our program + *_, last_field = self._get_signature(p_new).fields.keys() + updated_signature = self._get_signature(p_new).with_instructions(selected_instruction).with_updated_fields(last_field, prefix=selected_prefix) + self._set_signature(p_new, updated_signature) - # Get the selected demos - if demo_candidates: selected_demos = p_demo_candidates[demos_idx] + # Get the selected demos + if demo_candidates: selected_demos = p_demo_candidates[demos_idx] - # Use these demos in our program - if demo_candidates: p_new.demos = selected_demos + # Use these demos in our program + if demo_candidates: p_new.demos = selected_demos - # breakpoint() - - if self.verbose: print("Evaling the following program:") - # breakpoint() - if self.verbose: self._print_full_program(candidate_program) - trial_logs[trial_num]["program"] = candidate_program - - # Evaluate with the new prompts - total_score = 0 - batch_size = 100 - num_batches = math.ceil(len(trainset) / batch_size) - - for i in range(num_batches): - start_index = i * batch_size - end_index = min((i + 1) * batch_size, len(trainset)) - split_trainset = trainset[start_index:end_index] - split_score = evaluate(candidate_program, devset=split_trainset, display_table=0) - if self.verbose: print(f"{i}st split score: {split_score}") - - total_score += split_score * len(split_trainset) - curr_weighted_avg_score = total_score / min((i+1)*100,len(trainset)) - if self.verbose: print(f"curr average score: {curr_weighted_avg_score}") - - trial.report(curr_weighted_avg_score, i) - - # Handle pruning based on the intermediate value. - if trial.should_prune(): - print("Trial pruned.") - trial_logs[trial_num]["score"] = curr_weighted_avg_score - trial_logs[trial_num]["pruned"] = True - trial_num += 1 - raise optuna.TrialPruned() - - if self.verbose: print(f"Fully evaled score: {curr_weighted_avg_score}") - if self.verbose: self._print_model_history(self.task_model, n=1) # breakpoint() - score = curr_weighted_avg_score - - trial_logs[trial_num]["score"] = curr_weighted_avg_score - trial_logs[trial_num]["pruned"] = False - # Update the best program if the current score is better - if score > best_score: - best_score = score - best_program = candidate_program.deepcopy() - - trial_num += 1 + if self.verbose: print("Evaling the following program:") + # breakpoint() + if self.verbose: self._print_full_program(candidate_program) + trial_logs[trial_num]["program"] = candidate_program + + # Evaluate with the new prompts + total_score = 0 + batch_size = 100 + num_batches = math.ceil(len(trainset) / batch_size) + + for i in range(num_batches): + start_index = i * batch_size + end_index = min((i + 1) * batch_size, len(trainset)) + split_trainset = trainset[start_index:end_index] + split_score = evaluate(candidate_program, devset=split_trainset, display_table=0) + if self.verbose: print(f"{i}st split score: {split_score}") + + total_score += split_score * len(split_trainset) + curr_weighted_avg_score = total_score / min((i+1)*100,len(trainset)) + if self.verbose: print(f"curr average score: {curr_weighted_avg_score}") + + trial.report(curr_weighted_avg_score, i) + + # Handle pruning based on the intermediate value. + if trial.should_prune(): + print("Trial pruned.") + trial_logs[trial_num]["score"] = curr_weighted_avg_score + trial_logs[trial_num]["pruned"] = True + trial_num += 1 + raise optuna.TrialPruned() + + if self.verbose: print(f"Fully evaled score: {curr_weighted_avg_score}") + if self.verbose: self._print_model_history(self.task_model, n=1) + # breakpoint() + score = curr_weighted_avg_score + + trial_logs[trial_num]["score"] = curr_weighted_avg_score + trial_logs[trial_num]["pruned"] = False + + # Update the best program if the current score is better + if score > best_score: + best_score = score + best_program = candidate_program.deepcopy() + + trial_num += 1 - return score + return score - return objective + return objective - # Run the trial - objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, trainset) - sampler = optuna.samplers.TPESampler(seed=seed) - study = optuna.create_study(direction="maximize", sampler=sampler) - score = study.optimize(objective_function, n_trials=num_trials) + # Run the trial + objective_function = create_objective(module, instruction_candidates, demo_candidates, evaluate, trainset) + sampler = optuna.samplers.TPESampler(seed=seed) + study = optuna.create_study(direction="maximize", sampler=sampler) + score = study.optimize(objective_function, n_trials=num_trials) - if best_program is not None and self.track_stats: - best_program.trial_logs = trial_logs + if best_program is not None and self.track_stats: + best_program.trial_logs = trial_logs - print(f"Returning {best_program} from continue_program") - return best_program \ No newline at end of file + print(f"Returning {best_program} from continue_program") + return best_program \ No newline at end of file diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index e7cfac21a..9ba1da92c 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -34,7 +34,7 @@ class SignatureOptimizer(COPRO): def __init__(self, prompt_model=None, metric=None, breadth=10, depth=3, init_temperature=1.4, verbose=False, track_stats=False): - print(u"\u001b[31m[WARNING] SignatureOptimizer has been deprecated and replaced with COPRO. SignatureOptimizer will be removed in a future release. \u001b[31m") + print("\u001b[31m[WARNING] SignatureOptimizer has been deprecated and replaced with COPRO. SignatureOptimizer will be removed in a future release. \u001b[31m") super().__init__(prompt_model, metric, breadth, depth, init_temperature, verbose, track_stats) def compile(self, student, *, devset, eval_kwargs): diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index 82d92fc9e..1e08042f7 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -1,4 +1,3 @@ -import warnings from dspy.teleprompt.mipro_optimizer import MIPRO @@ -38,7 +37,7 @@ class BayesianSignatureOptimizer(MIPRO): def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): - print(u"\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") + print("\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) From f9f35b68d05565634e72f173f61561cee37bbc6c Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 15:12:17 -0800 Subject: [PATCH 30/79] fixing some variable names in test --- tests/teleprompt/test_signature_opt_bayesian.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/teleprompt/test_signature_opt_bayesian.py b/tests/teleprompt/test_signature_opt_bayesian.py index 38f560da4..63baf7a5b 100644 --- a/tests/teleprompt/test_signature_opt_bayesian.py +++ b/tests/teleprompt/test_signature_opt_bayesian.py @@ -82,7 +82,7 @@ def basic_request(self, prompt, num_candidates=1, **kwargs): print("===") dummy_response = {"choices": []} - for _ in range(n): + for _ in range(num_candidates): dummy_response["choices"].append( { "text": answer, @@ -117,7 +117,7 @@ def test_bayesian_signature_optimizer_initialization(): metric=simple_metric, num_candidates=10, init_temperature=1.4, verbose=True, track_stats=True ) assert optimizer.metric == simple_metric, "Metric not correctly initialized" - assert optimizer.n == 10, "Incorrect 'n' parameter initialization" + assert optimizer.num_candidates == 10, "Incorrect 'num_candidates' parameter initialization" assert ( optimizer.init_temperature == 1.4 ), "Initial temperature not correctly initialized" From bbaa0ac890507765e309920a365bbaf15a906046 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 15:14:58 -0800 Subject: [PATCH 31/79] fixing variable name --- dspy/teleprompt/mipro_optimizer.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index 3612b0962..1ff76f816 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -104,7 +104,7 @@ class DatasetDescriptorWithPriorObservations(dspy.Signature): class MIPRO(Teleprompter): def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, num_candidates=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): - self.n = num_candidates + self.num_candidates = num_candidates self.metric = metric self.init_temperature = init_temperature self.prompt_model = prompt_model if prompt_model is not None else dspy.settings.lm @@ -226,7 +226,7 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo if 1 not in example_sets[id(predictor)].keys(): raise ValueError("No examples found for the given predictor") instruct = None - for i in range(1, self.n): + for i in range(1, self.num_candidates): new_instruct = dspy.Predict( BasicGenerateInstructionWithExamplesAndDataObservations, n=1, @@ -247,7 +247,7 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo # Just examples elif view_examples: instruct = None - for i in range(1,self.n): # Note: skip over the first example set which is empty + for i in range(1,self.num_candidates): # Note: skip over the first example set which is empty new_instruct = dspy.Predict( BasicGenerateInstructionWithExamples, n=1, @@ -285,7 +285,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo random.seed(seed) estimated_task_model_calls_wo_module_calls = len(trainset) * num_trials # M * T * P - estimated_prompt_model_calls = 10 + self.n * len(student.predictors()) # num data summary calls + N * P + estimated_prompt_model_calls = 10 + self.num_candidates * len(student.predictors()) # num data summary calls + N * P user_message = textwrap.dedent(f"""\ {YELLOW}{BOLD}WARNING: Projected Language Model (LM) Calls{ENDC} @@ -293,7 +293,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo Please be advised that based on the parameters you have set, the maximum number of LM calls is projected as follows: {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{num_trials}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} - {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.n}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} + {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.num_candidates}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} {YELLOW}{BOLD}Estimated Cost Calculation:{ENDC} @@ -342,14 +342,14 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo # Generate N few shot example sets demo_candidates = {} - for i in range(self.n): + for i in range(self.num_candidates): if i == 0: # Story empty set of demos as default for index 0 for module_p in module.predictors(): if id(module_p) not in demo_candidates: demo_candidates[id(module_p)] = [] demo_candidates[id(module_p)].append([]) else: - if self.verbose: print(f"Creating basic bootstrap: {i}/{self.n-1}") + if self.verbose: print(f"Creating basic bootstrap: {i}/{self.num_candidates-1}") # Create a new basic bootstrap few - shot program . rng = random.Random(i) @@ -365,7 +365,7 @@ def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demo demo_candidates[id(module_p)].append(candidate_p.demos) # Generate N candidate prompts - instruction_candidates, _ = self._generate_first_N_candidates(module, self.n, view_data, view_examples, demo_candidates, trainset) + instruction_candidates, _ = self._generate_first_N_candidates(module, self.num_candidates, view_data, view_examples, demo_candidates, trainset) # Reset demo_candidates to None for our optimization if the user asked for no fewshot examples if max_bootstrapped_demos==0 and max_labeled_demos==0: From 39f5ba3729efbbeb609b3cdd803e3ee5d3ffa595 Mon Sep 17 00:00:00 2001 From: Herumb Shandilya Date: Fri, 8 Mar 2024 04:50:07 +0530 Subject: [PATCH 32/79] adding api references and docs files for functional --- docs/api/functional/_category_.json | 8 ++ docs/api/functional/dspy_TypedCoT.md | 41 ++++++++++ docs/api/functional/dspy_TypedPredictor.md | 78 +++++++++++++++++++ docs/api/functional/dspy_cot.md | 34 ++++++++ docs/api/functional/dspy_predictor.md | 30 +++++++ .../language_model_clients/_category_.json | 2 +- docs/api/optimizers/_category_.json | 2 +- .../retrieval_model_clients/_category_.json | 2 +- .../building-blocks/8-typed_predictors.md | 13 ++++ .../typed_predictors/_category_.json | 0 .../functional_typed_predictors.md | 7 ++ .../understanding_predictors.md | 9 +++ 12 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 docs/api/functional/_category_.json create mode 100644 docs/api/functional/dspy_TypedCoT.md create mode 100644 docs/api/functional/dspy_TypedPredictor.md create mode 100644 docs/api/functional/dspy_cot.md create mode 100644 docs/api/functional/dspy_predictor.md create mode 100644 docs/docs/building-blocks/8-typed_predictors.md create mode 100644 docs/docs/deep-dive/typed_predictors/_category_.json create mode 100644 docs/docs/deep-dive/typed_predictors/functional_typed_predictors.md create mode 100644 docs/docs/deep-dive/typed_predictors/understanding_predictors.md diff --git a/docs/api/functional/_category_.json b/docs/api/functional/_category_.json new file mode 100644 index 000000000..70bd70104 --- /dev/null +++ b/docs/api/functional/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Functional", + "position": 2, + "link": { + "type": "generated-index", + "description": "This documentation provides an overview of the Typed Predictors." + } +} \ No newline at end of file diff --git a/docs/api/functional/dspy_TypedCoT.md b/docs/api/functional/dspy_TypedCoT.md new file mode 100644 index 000000000..e728bdad0 --- /dev/null +++ b/docs/api/functional/dspy_TypedCoT.md @@ -0,0 +1,41 @@ +--- +sidebar_position: 2 +--- + +# dspy.TypedChainOfThought + +### Overview + +#### `def TypedChainOfThought(signature, max_retries=3) -> dspy.Module` + +Adds a Chain of Thoughts `dspy.OutputField` to the `dspy.TypedPredictor` module by prepending it to the Signature. Similar to `dspy.TypedPredictor` but automatically adds a "reasoning" output field. + +* **Inputs**: + * `signature`: The `dspy.Signature` specifying the input/output fields + * `max_retries`: Maximum number of retries if outputs fail validation +* **Output**: A dspy.Module instance capable of making predictions. + +### Example + +```python +from dspy import InputField, OutputField, Signature +from dspy.functional import TypedChainOfThought +from pydantic import BaseModel + +# We define a pydantic type that automatically checks if it's argument is valid python code. +class CodeOutput(BaseModel): + code: str + api_reference: str + +class CodeSignature(Signature): + function_description: str = InputField() + solution: CodeOutput = OutputField() + +cot_predictor = TypedChainOfThought(CodeSignature) +prediction = cot_predictor( + function_description="Write a function that adds two numbers." +) + +print(prediction["code"]) +print(prediction["api_reference"]) +``` \ No newline at end of file diff --git a/docs/api/functional/dspy_TypedPredictor.md b/docs/api/functional/dspy_TypedPredictor.md new file mode 100644 index 000000000..8e5fd5857 --- /dev/null +++ b/docs/api/functional/dspy_TypedPredictor.md @@ -0,0 +1,78 @@ +--- +sidebar_position: 1 +--- + +# dspy.TypedPredictor + +The `TypedPredictor` class is a sophisticated module designed for making predictions with strict type validations. It leverages a signature to enforce type constraints on inputs and outputs, ensuring that the data follows to the expected schema. + +### Constructor + +```python +TypedPredictor( + CodeSignature + max_retries=3 +) +``` + +Parameters: +* `signature` (dspy.Signature): The signature that defines the input and output fields along with their types. +* `max_retries` (int, optional): The maximum number of retries for generating a valid prediction output. Defaults to 3. + +### Methods + +#### `copy() -> "TypedPredictor"` + +Creates and returns a deep copy of the current TypedPredictor instance. + +**Returns:** A new instance of TypedPredictor that is a deep copy of the original instance. + +#### `_make_example(type_: Type) -> str` + +A static method that generates a JSON object example based pn the schema of the specified Pydantic model type. This JSON object serves as an example for the expected input or output format. + +**Parameters:** +* `type_`: A Pydantic model class for which an example JSON object is to be generated. + +**Returns:** A string that represents a JSON object example, which validates against the provided Pydantic model's JSON schema. If the method is unable to generate a valid example, it returns an empty string. + +#### `_prepare_signature() -> dspy.Signature` + +Prepares and returns a modified version of the signature associated with the TypedPredictor instance. This method iterates over the signature's fields to add format and parser functions based on their type annotations. + +**Returns:** A dspy.Signature object that has been enhanced with formatting and parsing specifications for its fields. + +#### `forward(**kwargs) -> dspy.Prediction` + +Executes the prediction logic, making use of the `dspy.Predict` component to generate predictions based on the input arguments. This method handles type validation, parsing of output data, and implements retry logic in case the output does not initially follow to the specified output schema. + +**Parameters:** + +* `**kwargs`: Keyword arguments corresponding to the input fields defined in the signature. + +**Returns:** A dspy.Prediction object containing the prediction results. Each key in this object corresponds to an output field defined in the signature, and its value is the parsed result of the prediction. + +### Example + +```python +from dspy import InputField, OutputField, Signature +from dspy.functional import TypedPredictor +from pydantic import BaseModel + +# We define a pydantic type that automatically checks if it's argument is valid python code. +class CodeOutput(BaseModel): + code: str + api_reference: str + +class CodeSignature(Signature): + function_description: str = InputField() + solution: CodeOutput = OutputField() + +cot_predictor = TypedPredictor(CodeSignature) +prediction = cot_predictor( + function_description="Write a function that adds two numbers." +) + +print(prediction["code"]) +print(prediction["api_reference"]) +``` \ No newline at end of file diff --git a/docs/api/functional/dspy_cot.md b/docs/api/functional/dspy_cot.md new file mode 100644 index 000000000..9b9e3bbea --- /dev/null +++ b/docs/api/functional/dspy_cot.md @@ -0,0 +1,34 @@ +--- +sidebar_position: 4 +--- + +--- +sidebar_position: 3 +--- + +# dspy.cot + +### Overview + +#### `def cot(func) -> dspy.Module` + +The `@cot` decorator is used to create a Chain of Thoughts module based on the provided function. It automatically generates a `dspy.TypedPredictor` and from the function's type annotations and docstring. Similar to predictor, but adds a "Reasoning" output field to capture the model's step-by-step thinking. + +* **Input**: Function with input parameters and return type annotation. +* **Output**: A dspy.Module instance capable of making predictions. + +### Example + +```python +import dspy + +context = ["Roses are red.", "Violets are blue"] +question = "What color are roses?" + +@dspy.cot +def generate_answer(self, context: list[str], question) -> str: + """Answer questions with short factoid answers.""" + pass + +generate_answer(context=context, question=question) +``` \ No newline at end of file diff --git a/docs/api/functional/dspy_predictor.md b/docs/api/functional/dspy_predictor.md new file mode 100644 index 000000000..9d4814c0f --- /dev/null +++ b/docs/api/functional/dspy_predictor.md @@ -0,0 +1,30 @@ +--- +sidebar_position: 3 +--- + +# dspy.predictor + +### Overview + +#### `def predictor(func) -> dspy.Module` + +The `@predictor` decorator is used to create a predictor module based on the provided function. It automatically generates a `dspy.TypedPredictor` and from the function's type annotations and docstring. + +* **Input**: Function with input parameters and return type annotation. +* **Output**: A dspy.Module instance capable of making predictions. + +### Example + +```python +import dspy + +context = ["Roses are red.", "Violets are blue"] +question = "What color are roses?" + +@dspy.predictor +def generate_answer(self, context: list[str], question) -> str: + """Answer questions with short factoid answers.""" + pass + +generate_answer(context=context, question=question) +``` \ No newline at end of file diff --git a/docs/api/language_model_clients/_category_.json b/docs/api/language_model_clients/_category_.json index 3f6129bae..1527ce187 100644 --- a/docs/api/language_model_clients/_category_.json +++ b/docs/api/language_model_clients/_category_.json @@ -1,6 +1,6 @@ { "label": "Language Model API Clients", - "position": 4, + "position": 5, "link": { "type": "generated-index", "description": "This documentation provides an overview of the DSPy Language Model Clients." diff --git a/docs/api/optimizers/_category_.json b/docs/api/optimizers/_category_.json index 5d7edc9df..8f98c5b3b 100644 --- a/docs/api/optimizers/_category_.json +++ b/docs/api/optimizers/_category_.json @@ -1,6 +1,6 @@ { "label": "Optimizers", - "position": 2, + "position": 3, "link": { "type": "generated-index", "description": "Teleprompters are powerful optimizers (included in DSPy) that can learn to bootstrap and select effective prompts for the modules of any program. (The \"tele-\" in the name means \"at a distance\", i.e., automatic prompting at a distance.)\n\nThis documentation provides an overview of the DSPy Teleprompters." diff --git a/docs/api/retrieval_model_clients/_category_.json b/docs/api/retrieval_model_clients/_category_.json index 0c3ec89a3..964dab01b 100644 --- a/docs/api/retrieval_model_clients/_category_.json +++ b/docs/api/retrieval_model_clients/_category_.json @@ -1,6 +1,6 @@ { "label": "Retrieval Model Clients", - "position": 3, + "position": 4, "link": { "type": "generated-index", "description": "This documentation provides an overview of the DSPy Retrieval Model Clients." diff --git a/docs/docs/building-blocks/8-typed_predictors.md b/docs/docs/building-blocks/8-typed_predictors.md new file mode 100644 index 000000000..65032474b --- /dev/null +++ b/docs/docs/building-blocks/8-typed_predictors.md @@ -0,0 +1,13 @@ +# Typed Predictors + +In DSPy, alongside Signatures a + +## Executing Typed Predictors + +## Chain of Thoughts with Typed Predictors + +## Optimizing Typed Predictors + +## Typed Predictors via Decorators + +## Composing Functional Typed Predictors in `dspy.Module` \ No newline at end of file diff --git a/docs/docs/deep-dive/typed_predictors/_category_.json b/docs/docs/deep-dive/typed_predictors/_category_.json new file mode 100644 index 000000000..e69de29bb diff --git a/docs/docs/deep-dive/typed_predictors/functional_typed_predictors.md b/docs/docs/deep-dive/typed_predictors/functional_typed_predictors.md new file mode 100644 index 000000000..9a8f79ae9 --- /dev/null +++ b/docs/docs/deep-dive/typed_predictors/functional_typed_predictors.md @@ -0,0 +1,7 @@ +# Functional Typed Predictors + +## Typed Predictors as Decorators + +## Functional Typed Predictors in `dspy.Module` + +## How Functional Typed Predictors work? \ No newline at end of file diff --git a/docs/docs/deep-dive/typed_predictors/understanding_predictors.md b/docs/docs/deep-dive/typed_predictors/understanding_predictors.md new file mode 100644 index 000000000..f0ad17354 --- /dev/null +++ b/docs/docs/deep-dive/typed_predictors/understanding_predictors.md @@ -0,0 +1,9 @@ +# Understanding Typed Predictors + +## Why use a Typed Predictor? + +## How to use a Typed Predictor? + +## Prompt of Typed Predictors + +## How Typed Predictors work? \ No newline at end of file From 2b2ad809c0678d187eca2cb6cee89aa35570ecc2 Mon Sep 17 00:00:00 2001 From: VivHarsha <101607940+VivHarsha@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:37:10 -0800 Subject: [PATCH 33/79] Update provider name to Claude or Bedrock --- dsp/modules/bedrock.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dsp/modules/bedrock.py b/dsp/modules/bedrock.py index ac8b42d2d..02fc78a1f 100644 --- a/dsp/modules/bedrock.py +++ b/dsp/modules/bedrock.py @@ -34,6 +34,7 @@ def __init__( batch_n=True, # Bedrock does not support the `n` parameter ) self._validate_model(model) + self.provider = "claude" if "claude" in model.lower() else "bedrock" def _validate_model(self, model: str) -> None: if "claude" not in model.lower(): From 8b5dd0eb5c9fc59717cb8d56465348817b749994 Mon Sep 17 00:00:00 2001 From: VivHarsha <101607940+VivHarsha@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:41:21 -0800 Subject: [PATCH 34/79] Inspect history for Claude models --- dsp/modules/lm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsp/modules/lm.py b/dsp/modules/lm.py index fb0b0aab5..5fbf5ec5e 100644 --- a/dsp/modules/lm.py +++ b/dsp/modules/lm.py @@ -46,7 +46,7 @@ def inspect_history(self, n: int = 1, skip: int = 0): if prompt != last_prompt: - if provider == "clarifai" or provider == "google": + if provider == "clarifai" or provider == "google" or provider == "claude": printed.append( ( prompt, @@ -80,7 +80,7 @@ def inspect_history(self, n: int = 1, skip: int = 0): text = choices[0].text elif provider == "openai" or provider == "ollama": text = ' ' + self._get_choice_text(choices[0]).strip() - elif provider == "clarifai": + elif provider == "clarifai" or provider == "claude" : text=choices elif provider == "google": text = choices[0].parts[0].text From a5f75af4339ebff5cda56d558412ba8a798670e1 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 21:39:13 -0800 Subject: [PATCH 35/79] updating tests for new optimizers --- tests/teleprompt/test_signature_opt.py | 24 ++++++++-------- .../teleprompt/test_signature_opt_bayesian.py | 28 +++++++++++++------ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/tests/teleprompt/test_signature_opt.py b/tests/teleprompt/test_signature_opt.py index d7f347551..c0fe712bc 100644 --- a/tests/teleprompt/test_signature_opt.py +++ b/tests/teleprompt/test_signature_opt.py @@ -1,6 +1,6 @@ import textwrap import dspy -from dspy.teleprompt.signature_opt import SignatureOptimizer +from dspy.teleprompt.signature_opt import COPRO from dspy.utils.dummies import DummyLM from dspy import Example @@ -16,7 +16,7 @@ def simple_metric(example, prediction): ] def test_signature_optimizer_initialization(): - optimizer = SignatureOptimizer(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) + optimizer = COPRO(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) assert optimizer.metric == simple_metric, "Metric not correctly initialized" assert optimizer.breadth == 2, "Breadth not correctly initialized" assert optimizer.depth == 1, "Depth not correctly initialized" @@ -25,20 +25,20 @@ def test_signature_optimizer_initialization(): class SimpleModule(dspy.Module): def __init__(self, signature): super().__init__() - # SignatureOptimizer doesn't work with dspy.Predict + # COPRO doesn't work with dspy.Predict self.predictor = dspy.ChainOfThought(signature) def forward(self, **kwargs): return self.predictor(**kwargs) def test_signature_optimizer_optimization_process(): - optimizer = SignatureOptimizer(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) + optimizer = COPRO(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) dspy.settings.configure(lm=DummyLM(["Optimized instruction 1", "Optimized instruction 2"])) student = SimpleModule("input -> output") - # Assuming the compile method of SignatureOptimizer requires a student module, a development set, and evaluation kwargs - optimized_student = optimizer.compile(student, devset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) + # Assuming the compile method of COPRO requires a student module, a development set, and evaluation kwargs + optimized_student = optimizer.compile(student, trainset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) # Check that the optimized student has been modified from the original # This check can be more specific based on how the optimization modifies the student @@ -48,12 +48,12 @@ def test_signature_optimizer_optimization_process(): # such as checking the instructions of the optimized student's predictors. def test_signature_optimizer_statistics_tracking(): - optimizer = SignatureOptimizer(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) + optimizer = COPRO(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) optimizer.track_stats = True # Enable statistics tracking dspy.settings.configure(lm=DummyLM(["Optimized instruction"])) student = SimpleModule("input -> output") - optimized_student = optimizer.compile(student, devset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) + optimized_student = optimizer.compile(student, trainset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) # Verify that statistics have been tracked and attached to the optimized student assert hasattr(optimized_student, 'total_calls'), "Total calls statistic not tracked" @@ -67,12 +67,12 @@ def test_optimization_and_output_verification(): "Optimized Prefix", ]) dspy.settings.configure(lm=lm) - optimizer = SignatureOptimizer(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) + optimizer = COPRO(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) student = SimpleModule("input -> output") # Compile the student with the optimizer - optimized_student = optimizer.compile(student, devset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) + optimized_student = optimizer.compile(student, trainset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) # Simulate calling the optimized student with a new input test_input = "What is the capital of France?" @@ -102,11 +102,11 @@ def test_optimization_and_output_verification(): def test_statistics_tracking_during_optimization(): dspy.settings.configure(lm=DummyLM(["Optimized instruction for stats tracking"])) - optimizer = SignatureOptimizer(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) + optimizer = COPRO(metric=simple_metric, breadth=2, depth=1, init_temperature=1.4) optimizer.track_stats = True # Enable statistics tracking student = SimpleModule("input -> output") - optimized_student = optimizer.compile(student, devset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) + optimized_student = optimizer.compile(student, trainset=trainset, eval_kwargs={"num_threads": 1, "display_progress": False}) # Verify that statistics have been tracked assert hasattr(optimized_student, 'total_calls'), "Optimizer did not track total metric calls" diff --git a/tests/teleprompt/test_signature_opt_bayesian.py b/tests/teleprompt/test_signature_opt_bayesian.py index 63baf7a5b..c1cb61de0 100644 --- a/tests/teleprompt/test_signature_opt_bayesian.py +++ b/tests/teleprompt/test_signature_opt_bayesian.py @@ -53,10 +53,18 @@ def basic_request(self, prompt, num_candidates=1, **kwargs): answer = " summarizing..." else: pairs = re.findall(r"Input: (.*)\nOutput: (.*)", prompt) + # pairs = re.findall(r"(?<=\n|^)---\n\nInput: (.*?)\nOutput: (.*?)(?=\n\n---|\n*$)", prompt, re.DOTALL) + # pairs = re.findall(r"Input: (.*?)\n(?:Reasoning: .*?\n)?Output: (.*)", prompt, re.DOTALL) + pairs = re.findall(r"Input: (.*?)\n(?:Reasoning:.*?\n)?Output: (.*?)\n", prompt, re.DOTALL) + + # breakpoint() print("PROMPT:", prompt) print("PAIRS:", pairs) + # if "What is the capital of Spain?" in prompt: + # breakpoint() + last = re.search(r"Input: (.*)\nReasoning: (.*)$", prompt) current_question = last.group(1) @@ -227,34 +235,34 @@ def test_optimization_and_output_verification(): assert prediction.output == "Madrid" - assert lm.get_convo(-1) == textwrap.dedent( + expected_lm_output = textwrap.dedent( """\ Input: --- - + Follow the following format. - + Input: ${input} Reasoning: Let's think step by step in order to ${produce the output}. We ... Output: ${output} --- - Input: What is the capital of Norway? + Input: What is the capital of France? Reasoning: Let's think step by step in order to think deeply. - Output: Oslo + Output: Paris --- - Input: What is the capital of Sweden? + Input: What is the capital of Norway? Reasoning: Let's think step by step in order to think deeply. - Output: Stockholm + Output: Oslo --- - Input: What is the capital of France? - Output: Paris + Input: What does the fox say? + Output: Ring-ding-ding-ding-dingeringeding! --- @@ -262,3 +270,5 @@ def test_optimization_and_output_verification(): Reasoning: Let's think step by step in order to think deeply. Output: Madrid""" ) + + assert lm.get_convo(-1) == expected_lm_output \ No newline at end of file From 8e13bd9033260e105e8c3b28728ea5ee4bc5788c Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 21:45:50 -0800 Subject: [PATCH 36/79] renaming tests --- .../{test_signature_opt.py => test_copro_optimizer.py} | 0 ...t_signature_opt_bayesian.py => test_mipro_optimizer.py} | 7 ------- 2 files changed, 7 deletions(-) rename tests/teleprompt/{test_signature_opt.py => test_copro_optimizer.py} (100%) rename tests/teleprompt/{test_signature_opt_bayesian.py => test_mipro_optimizer.py} (95%) diff --git a/tests/teleprompt/test_signature_opt.py b/tests/teleprompt/test_copro_optimizer.py similarity index 100% rename from tests/teleprompt/test_signature_opt.py rename to tests/teleprompt/test_copro_optimizer.py diff --git a/tests/teleprompt/test_signature_opt_bayesian.py b/tests/teleprompt/test_mipro_optimizer.py similarity index 95% rename from tests/teleprompt/test_signature_opt_bayesian.py rename to tests/teleprompt/test_mipro_optimizer.py index c1cb61de0..17e94a580 100644 --- a/tests/teleprompt/test_signature_opt_bayesian.py +++ b/tests/teleprompt/test_mipro_optimizer.py @@ -52,19 +52,12 @@ def basic_request(self, prompt, num_candidates=1, **kwargs): elif prompt.endswith("Summary:"): answer = " summarizing..." else: - pairs = re.findall(r"Input: (.*)\nOutput: (.*)", prompt) - # pairs = re.findall(r"(?<=\n|^)---\n\nInput: (.*?)\nOutput: (.*?)(?=\n\n---|\n*$)", prompt, re.DOTALL) - - # pairs = re.findall(r"Input: (.*?)\n(?:Reasoning: .*?\n)?Output: (.*)", prompt, re.DOTALL) pairs = re.findall(r"Input: (.*?)\n(?:Reasoning:.*?\n)?Output: (.*?)\n", prompt, re.DOTALL) # breakpoint() print("PROMPT:", prompt) print("PAIRS:", pairs) - # if "What is the capital of Spain?" in prompt: - # breakpoint() - last = re.search(r"Input: (.*)\nReasoning: (.*)$", prompt) current_question = last.group(1) From 063a1446b76bb7b3b40bb456eec0bbaec8270890 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 21:48:00 -0800 Subject: [PATCH 37/79] small cleanup of breakpoints --- dspy/teleprompt/mipro_optimizer.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index 1ff76f816..3125c562c 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -415,11 +415,8 @@ def objective(trial): # Use these demos in our program if demo_candidates: p_new.demos = selected_demos - - # breakpoint() if self.verbose: print("Evaling the following program:") - # breakpoint() if self.verbose: self._print_full_program(candidate_program) trial_logs[trial_num]["program"] = candidate_program @@ -451,7 +448,6 @@ def objective(trial): if self.verbose: print(f"Fully evaled score: {curr_weighted_avg_score}") if self.verbose: self._print_model_history(self.task_model, n=1) - # breakpoint() score = curr_weighted_avg_score trial_logs[trial_num]["score"] = curr_weighted_avg_score From b8bb02160cc2f116e9df96c3a400d23941b5e570 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Thu, 7 Mar 2024 22:51:10 -0800 Subject: [PATCH 38/79] minor updates --- dspy/teleprompt/copro_optimizer.py | 372 +++++++++++-------- dspy/teleprompt/signature_opt_bayesian.py | 2 +- examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb | 143 +++---- 3 files changed, 285 insertions(+), 232 deletions(-) diff --git a/dspy/teleprompt/copro_optimizer.py b/dspy/teleprompt/copro_optimizer.py index 9d304cf9e..49a6ff438 100644 --- a/dspy/teleprompt/copro_optimizer.py +++ b/dspy/teleprompt/copro_optimizer.py @@ -117,185 +117,237 @@ def compile(self, student, *, trainset, eval_kwargs): results_best = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} results_latest = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} - if self.track_stats: - import numpy as np - - - candidates = {} - evaluated_candidates = defaultdict(dict) - - # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts - for predictor in module.predictors(): - basic_instruction = None - basic_prefix = None - *_, last_key = self._get_signature(predictor).fields.keys() - basic_instruction = self._get_signature(predictor).instructions - basic_prefix = self._get_signature(predictor).fields[last_key].json_schema_extra['prefix'] - if self.prompt_model: - with dspy.settings.context(lm=self.prompt_model): - instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) - else: - instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) - # Add in our initial prompt as a candidate as well - instruct.completions.proposed_instruction.append(basic_instruction) - instruct.completions.proposed_prefix_for_output_field.append(basic_prefix) - candidates[id(predictor)] = instruct.completions - evaluated_candidates[id(predictor)] = {} + # Define ANSI escape codes for colors + YELLOW = '\033[93m' + BLUE = '\033[94m' + BOLD = '\033[1m' + ENDC = '\033[0m' # Resets the color to default + + random.seed(seed) - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + estimated_task_model_calls_wo_module_calls = len(trainset) * num_trials # M * T * P + estimated_prompt_model_calls = 10 + self.num_candidates * len(student.predictors()) # num data summary calls + N * P + + user_message = textwrap.dedent(f"""\ + {YELLOW}{BOLD}WARNING: Projected Language Model (LM) Calls{ENDC} + + Please be advised that based on the parameters you have set, the maximum number of LM calls is projected as follows: + + {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{num_trials}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} + {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.num_candidates}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} + + {YELLOW}{BOLD}Estimated Cost Calculation:{ENDC} - latest_candidates = candidates - all_candidates = candidates + {YELLOW}Total Cost = (Number of calls to task model * (Avg Input Token Length per Call * Task Model Price per Input Token + Avg Output Token Length per Call * Task Model Price per Output Token) + + (Number of calls to prompt model * (Avg Input Token Length per Call * Task Prompt Price per Input Token + Avg Output Token Length per Call * Prompt Model Price per Output Token).{ENDC} + + For a preliminary estimate of potential costs, we recommend you perform your own calculations based on the task + and prompt models you intend to use. If the projected costs exceed your budget or expectations, you may consider: + + {YELLOW}- Reducing the number of trials (`num_trials`), the size of the trainset, or the number of LM calls in your program.{ENDC} + {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC}""") - module_clone = module.deepcopy() + user_confirmation_message = textwrap.dedent(f"""\ + To proceed with the execution of this program, please confirm by typing {BLUE}'y'{ENDC} for yes or {BLUE}'n'{ENDC} for no. - # For each iteration in depth... - for d in range(self.depth): # TODO: fix this so that we eval the new batch of predictors with the new best followoing predictors - print(f"Iteration Depth: {d+1}/{self.depth}.") + If you would like to bypass this confirmation step in future executions, set the {YELLOW}`requires_permission_to_run`{ENDC} flag to {YELLOW}`False`.{ENDC} - latest_scores = [] + {YELLOW}Awaiting your input...{ENDC} + """) + + print(user_message) - # Go through our module's predictors - for p_i, (p_old, p_new) in enumerate(zip(module.predictors(), module_clone.predictors())): - candidates_ = latest_candidates[id(p_old)] # Use the most recently generated candidates for evaluation - if len(module.predictors()) > 1: - candidates_ = all_candidates[id(p_old)] # Unless our program has multiple predictors, in which case we need to reevaluate all prompts with the new prompt(s) for the other predictor(s) - - # For each candidate - for c_i, c in enumerate(candidates_): - # Get the candidate instruction and prefix - instruction, prefix = c.proposed_instruction.strip('"').strip(), c.proposed_prefix_for_output_field.strip('"').strip() - - # Set this new module with our instruction / prefix - *_, last_key = self._get_signature(p_new).fields.keys() - updated_signature = self._get_signature(p_new) \ - .with_instructions(instruction) \ - .with_updated_fields(last_key, prefix=prefix) - self._set_signature(p_new, updated_signature) + sys.stdout.flush() # Flush the output buffer to force the message to print - # Score the instruction / prefix - if self.verbose: print("----------------") - for i,predictor in enumerate(module_clone.predictors()): - if self.verbose: print(f"Predictor {i+1}") - self._print_signature(predictor) - print(f"At Depth {d+1}/{self.depth}, Evaluating Prompt Candidate #{c_i+1}/{len(candidates_)} for Predictor {p_i+1} of {len(module.predictors())}.") - score = evaluate(module_clone, devset=trainset, **eval_kwargs) - if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") - total_calls += 1 - if self.verbose: print("----------------") - - replace_entry = True - if self.verbose: print(f"(instruction, prefix) {(instruction, prefix)}") - # if verbose: print(f"evaluated_candidates[id(p_old)] {evaluated_candidates[id(p_old)]}") - if ((instruction, prefix) in evaluated_candidates[id(p_old)]): - # if verbose: print(f"if evaluated_candidates[id(p_old)][(instruction, prefix)] {evaluated_candidates[id(p_old)][(instruction, prefix)]}") - if evaluated_candidates[id(p_old)][(instruction, prefix)]["score"] >= score: - replace_entry = False - - if replace_entry: - # Add it to our evaluated candidates list - evaluated_candidates[id(p_old)][(instruction, prefix)] = { - "score": score, - "program": module_clone.deepcopy(), - "instruction": instruction, - "prefix": prefix, - "depth": d, - } - - if (len(candidates_)-self.breadth <= c_i): - latest_scores.append(score) - if self.track_stats: - results_latest[id(p_old)]["depth"].append(d) - results_latest[id(p_old)]["max"].append(max(latest_scores)) - results_latest[id(p_old)]["average"].append(sum(latest_scores)/len(latest_scores)) - results_latest[id(p_old)]["min"].append(min(latest_scores)) - results_latest[id(p_old)]["std"].append(np.std(latest_scores)) - - # Now that we've evaluated the candidates, set this predictor to the best performing version - # to ensure the next round of scores reflect the best possible version - best_candidate = max(evaluated_candidates[id(p_old)].values(), key=lambda candidate: candidate['score']) - *_, last_key = self._get_signature(p_old).fields.keys() - updated_signature = self._get_signature(p_new) \ - .with_instructions(best_candidate["instruction"]) \ - .with_updated_fields(last_key, prefix=best_candidate["prefix"]) - self._set_signature(p_new, updated_signature) - if self.verbose: print(f"Updating Predictor {id(p_old)} to:\ni: {best_candidate['instruction']}\np: {best_candidate['prefix']}") - if self.verbose: print("Full predictor with update: ") - for i,predictor in enumerate(module_clone.predictors()): - if self.verbose: print(f"Predictor {i}") - self._print_signature(predictor) - - if d == self.depth-1: - break + run=True + if requires_permission_to_run: + print(user_confirmation_message) + user_input = input("Do you wish to continue? (y/n): ").strip().lower() + if user_input != 'y': + print("Compilation aborted by the user.") + run=False - - new_candidates = {} - for p_base in module.predictors(): - # Build Few-Shot Example of Optimized Prompts - attempts = [] - shortest_len = self.breadth - shortest_len = min(len(evaluated_candidates[id(p_base)]),shortest_len) - best_predictors = list(evaluated_candidates[id(p_base)].values()) + if run: + if self.track_stats: + import numpy as np - # best_predictors = evaluated_candidates[id(p_base)].values()[:] - best_predictors.sort(key=lambda x: x['score'], reverse=True) - if self.track_stats: - scores = [x['score'] for x in best_predictors][:10] - results_best[id(p_base)]["depth"].append(d) - results_best[id(p_base)]["max"].append(max(scores)) - results_best[id(p_base)]["average"].append(sum(scores)/len(scores)) - results_best[id(p_base)]["min"].append(min(scores)) - results_best[id(p_base)]["std"].append(np.std(scores)) - - for i in range(shortest_len-1,-1,-1): - # breakpoint() - attempts.append(f'Instruction #{shortest_len-i}: {best_predictors[i]["instruction"]}') - attempts.append(f'Prefix #{shortest_len-i}: {best_predictors[i]["prefix"]}') - attempts.append(f'Resulting Score #{shortest_len-i}: {best_predictors[i]["score"]}') - - # Generate next batch of potential prompts to optimize, with previous attempts as input + candidates = {} + evaluated_candidates = defaultdict(dict) + + # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts + for predictor in module.predictors(): + basic_instruction = None + basic_prefix = None + *_, last_key = self._get_signature(predictor).fields.keys() + basic_instruction = self._get_signature(predictor).instructions + basic_prefix = self._get_signature(predictor).fields[last_key].json_schema_extra['prefix'] if self.prompt_model: with dspy.settings.context(lm=self.prompt_model): - instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) + instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) else: - instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) + instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) + # Add in our initial prompt as a candidate as well + instruct.completions.proposed_instruction.append(basic_instruction) + instruct.completions.proposed_prefix_for_output_field.append(basic_prefix) + candidates[id(predictor)] = instruct.completions + evaluated_candidates[id(predictor)] = {} + + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - # Get candidates for each predictor - new_candidates[id(p_base)] = instr.completions - all_candidates[id(p_base)].proposed_instruction.extend(instr.completions.proposed_instruction) - all_candidates[id(p_base)].proposed_prefix_for_output_field.extend(instr.completions.proposed_prefix_for_output_field) + latest_candidates = candidates + all_candidates = candidates + + module_clone = module.deepcopy() - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - latest_candidates = new_candidates - - candidates = [] - for predictor in module.predictors(): - candidates.extend(list(evaluated_candidates[id(predictor)].values())) + # For each iteration in depth... + for d in range(self.depth): # TODO: fix this so that we eval the new batch of predictors with the new best followoing predictors + print(f"Iteration Depth: {d+1}/{self.depth}.") - if self.track_stats: - best_predictors = list(evaluated_candidates[id(predictor)].values()) - best_predictors.sort(key=lambda x: x['score'], reverse=True) + latest_scores = [] + + # Go through our module's predictors + for p_i, (p_old, p_new) in enumerate(zip(module.predictors(), module_clone.predictors())): + candidates_ = latest_candidates[id(p_old)] # Use the most recently generated candidates for evaluation + if len(module.predictors()) > 1: + candidates_ = all_candidates[id(p_old)] # Unless our program has multiple predictors, in which case we need to reevaluate all prompts with the new prompt(s) for the other predictor(s) + + # For each candidate + for c_i, c in enumerate(candidates_): + # Get the candidate instruction and prefix + instruction, prefix = c.proposed_instruction.strip('"').strip(), c.proposed_prefix_for_output_field.strip('"').strip() + + # Set this new module with our instruction / prefix + *_, last_key = self._get_signature(p_new).fields.keys() + updated_signature = self._get_signature(p_new) \ + .with_instructions(instruction) \ + .with_updated_fields(last_key, prefix=prefix) + self._set_signature(p_new, updated_signature) + + # Score the instruction / prefix + if self.verbose: print("----------------") + for i,predictor in enumerate(module_clone.predictors()): + if self.verbose: print(f"Predictor {i+1}") + self._print_signature(predictor) + print(f"At Depth {d+1}/{self.depth}, Evaluating Prompt Candidate #{c_i+1}/{len(candidates_)} for Predictor {p_i+1} of {len(module.predictors())}.") + score = evaluate(module_clone, devset=trainset, **eval_kwargs) + if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") + total_calls += 1 + if self.verbose: print("----------------") + + replace_entry = True + if self.verbose: print(f"(instruction, prefix) {(instruction, prefix)}") + # if verbose: print(f"evaluated_candidates[id(p_old)] {evaluated_candidates[id(p_old)]}") + if ((instruction, prefix) in evaluated_candidates[id(p_old)]): + # if verbose: print(f"if evaluated_candidates[id(p_old)][(instruction, prefix)] {evaluated_candidates[id(p_old)][(instruction, prefix)]}") + if evaluated_candidates[id(p_old)][(instruction, prefix)]["score"] >= score: + replace_entry = False + + if replace_entry: + # Add it to our evaluated candidates list + evaluated_candidates[id(p_old)][(instruction, prefix)] = { + "score": score, + "program": module_clone.deepcopy(), + "instruction": instruction, + "prefix": prefix, + "depth": d, + } + + if (len(candidates_)-self.breadth <= c_i): + latest_scores.append(score) + + if self.track_stats: + results_latest[id(p_old)]["depth"].append(d) + results_latest[id(p_old)]["max"].append(max(latest_scores)) + results_latest[id(p_old)]["average"].append(sum(latest_scores)/len(latest_scores)) + results_latest[id(p_old)]["min"].append(min(latest_scores)) + results_latest[id(p_old)]["std"].append(np.std(latest_scores)) + + # Now that we've evaluated the candidates, set this predictor to the best performing version + # to ensure the next round of scores reflect the best possible version + best_candidate = max(evaluated_candidates[id(p_old)].values(), key=lambda candidate: candidate['score']) + *_, last_key = self._get_signature(p_old).fields.keys() + updated_signature = self._get_signature(p_new) \ + .with_instructions(best_candidate["instruction"]) \ + .with_updated_fields(last_key, prefix=best_candidate["prefix"]) + self._set_signature(p_new, updated_signature) + if self.verbose: print(f"Updating Predictor {id(p_old)} to:\ni: {best_candidate['instruction']}\np: {best_candidate['prefix']}") + if self.verbose: print("Full predictor with update: ") + for i,predictor in enumerate(module_clone.predictors()): + if self.verbose: print(f"Predictor {i}") + self._print_signature(predictor) + + if d == self.depth-1: + break - scores = [x['score'] for x in best_predictors][:10] - results_best[id(predictor)]["depth"].append(d) - results_best[id(predictor)]["max"].append(max(scores)) - results_best[id(predictor)]["average"].append(sum(scores)/len(scores)) - results_best[id(predictor)]["min"].append(min(scores)) - results_best[id(predictor)]["std"].append(np.std(scores)) + + new_candidates = {} + for p_base in module.predictors(): + # Build Few-Shot Example of Optimized Prompts + attempts = [] + shortest_len = self.breadth + shortest_len = min(len(evaluated_candidates[id(p_base)]),shortest_len) + best_predictors = list(evaluated_candidates[id(p_base)].values()) + + # best_predictors = evaluated_candidates[id(p_base)].values()[:] + best_predictors.sort(key=lambda x: x['score'], reverse=True) + + if self.track_stats: + scores = [x['score'] for x in best_predictors][:10] + results_best[id(p_base)]["depth"].append(d) + results_best[id(p_base)]["max"].append(max(scores)) + results_best[id(p_base)]["average"].append(sum(scores)/len(scores)) + results_best[id(p_base)]["min"].append(min(scores)) + results_best[id(p_base)]["std"].append(np.std(scores)) + + for i in range(shortest_len-1,-1,-1): + # breakpoint() + attempts.append(f'Instruction #{shortest_len-i}: {best_predictors[i]["instruction"]}') + attempts.append(f'Prefix #{shortest_len-i}: {best_predictors[i]["prefix"]}') + attempts.append(f'Resulting Score #{shortest_len-i}: {best_predictors[i]["score"]}') + + # Generate next batch of potential prompts to optimize, with previous attempts as input + if self.prompt_model: + with dspy.settings.context(lm=self.prompt_model): + instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) + else: + instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) - # if verbose: print(f"candidates: {candidates}") - candidates.sort(key=lambda x: x['score'], reverse=True) + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + # Get candidates for each predictor + new_candidates[id(p_base)] = instr.completions + all_candidates[id(p_base)].proposed_instruction.extend(instr.completions.proposed_instruction) + all_candidates[id(p_base)].proposed_prefix_for_output_field.extend(instr.completions.proposed_prefix_for_output_field) - candidates = self._drop_duplicates(candidates) + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + latest_candidates = new_candidates + + candidates = [] + for predictor in module.predictors(): + candidates.extend(list(evaluated_candidates[id(predictor)].values())) - best_program = candidates[0]["program"] - best_program.candidate_programs = candidates - best_program.total_calls = total_calls - if self.track_stats: - best_program.results_best = results_best - best_program.results_latest = results_latest + if self.track_stats: + best_predictors = list(evaluated_candidates[id(predictor)].values()) + best_predictors.sort(key=lambda x: x['score'], reverse=True) + + scores = [x['score'] for x in best_predictors][:10] + results_best[id(predictor)]["depth"].append(d) + results_best[id(predictor)]["max"].append(max(scores)) + results_best[id(predictor)]["average"].append(sum(scores)/len(scores)) + results_best[id(predictor)]["min"].append(min(scores)) + results_best[id(predictor)]["std"].append(np.std(scores)) + + # if verbose: print(f"candidates: {candidates}") + candidates.sort(key=lambda x: x['score'], reverse=True) + + candidates = self._drop_duplicates(candidates) + + best_program = candidates[0]["program"] + best_program.candidate_programs = candidates + best_program.total_calls = total_calls + if self.track_stats: + best_program.results_best = results_best + best_program.results_latest = results_latest - return best_program \ No newline at end of file + return best_program \ No newline at end of file diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index 1e08042f7..5d009f86e 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -41,5 +41,5 @@ def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10 super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) - def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, optuna_trials_num, view_data=True, view_examples=True, requires_permission_to_run=True, num_trials=None): + def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, optuna_trials_num, view_data=True, view_examples=True, requires_permission_to_run=False, num_trials=None): return super().compile(student, trainset=devset, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, eval_kwargs=eval_kwargs, seed=seed, view_data=view_data, view_examples=view_examples, requires_permission_to_run=requires_permission_to_run, num_trials=optuna_trials_num) diff --git a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb index cb450d763..e50831c93 100644 --- a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb +++ b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb @@ -58,15 +58,66 @@ { "cell_type": "markdown", "metadata": { - "id": "rbGIXWcqqZH1" + "id": "5Vo4Tb9srSow" }, "source": [ - "First, we'll __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook. We'll also load in our pre optimized program from hugging face to inspect later." + "First, we will install __DSPy__ if it's not there already." ] }, { "cell_type": "code", "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JpijP_d7qZH2", + "outputId": "422dc4d0-4574-4e4b-935a-c7b4c875472f" + }, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import sys\n", + "import os\n", + "import regex as re\n", + "\n", + "try: # When on google Colab, let's clone the notebook so we download the cache.\n", + " import google.colab\n", + " repo_path = 'dspy'\n", + "\n", + " !git -C $repo_path pull origin || git clone https://github.com/stanfordnlp/dspy $repo_path\n", + "except:\n", + " repo_path = '.'\n", + "\n", + "if repo_path not in sys.path:\n", + " sys.path.append(repo_path)\n", + "\n", + "\n", + "import pkg_resources # Install the package if it's not installed\n", + "if not \"dspy-ai\" in {pkg.key for pkg in pkg_resources.working_set}:\n", + " !pip install -U pip\n", + " !pip install dspy-ai\n", + " !pip install openai~=0.28.1\n", + " !pip install -e $repo_path\n", + " !pip install --upgrade cloudpickle==3.0.0\n", + "\n", + "import dspy" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rbGIXWcqqZH1" + }, + "source": [ + "Then, we'll __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook. We'll also load in our pre optimized program from hugging face to inspect later." + ] + }, + { + "cell_type": "code", + "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -113,57 +164,6 @@ "os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = f\"{os.getcwd()}/MIPRO_notebook_cache\"" ] }, - { - "cell_type": "markdown", - "metadata": { - "id": "5Vo4Tb9srSow" - }, - "source": [ - "Next, we will install __DSPy__ if it's not there already." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "JpijP_d7qZH2", - "outputId": "422dc4d0-4574-4e4b-935a-c7b4c875472f" - }, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "import sys\n", - "import os\n", - "import regex as re\n", - "\n", - "try: # When on google Colab, let's clone the notebook so we download the cache.\n", - " import google.colab\n", - " repo_path = 'dspy'\n", - "\n", - " !git -C $repo_path pull origin || git clone https://github.com/stanfordnlp/dspy $repo_path\n", - "except:\n", - " repo_path = '.'\n", - "\n", - "if repo_path not in sys.path:\n", - " sys.path.append(repo_path)\n", - "\n", - "\n", - "import pkg_resources # Install the package if it's not installed\n", - "if not \"dspy-ai\" in {pkg.key for pkg in pkg_resources.working_set}:\n", - " !pip install -U pip\n", - " !pip install dspy-ai\n", - " !pip install openai~=0.28.1\n", - " !pip install -e $repo_path\n", - " !pip install --upgrade cloudpickle==3.0.0\n", - "\n", - "import dspy" - ] - }, { "cell_type": "markdown", "metadata": { @@ -182,6 +182,7 @@ "outputs": [], "source": [ "### NOTE: if you'd like to run this code without a cache, you can remove these lines to configure your OPEN AI key ###\n", + "# import openai\n", "# os.environ['OPENAI_API_KEY'] = \"TODO: ADD YOUR OPEN AI KEY HERE\"\n", "# openai.api_key = os.environ.get('OPENAI_API_KEY')\n", "# openai.api_base = \"https://api.openai.com/v1\"\n", @@ -432,15 +433,15 @@ "name": "stderr", "output_type": "stream", "text": [ - " 0%| | 0/500 [00:00 Date: Thu, 7 Mar 2024 22:54:38 -0800 Subject: [PATCH 39/79] removing accidentally added warning from copro --- dspy/teleprompt/copro_optimizer.py | 372 +++++++++++++---------------- 1 file changed, 160 insertions(+), 212 deletions(-) diff --git a/dspy/teleprompt/copro_optimizer.py b/dspy/teleprompt/copro_optimizer.py index 49a6ff438..9d304cf9e 100644 --- a/dspy/teleprompt/copro_optimizer.py +++ b/dspy/teleprompt/copro_optimizer.py @@ -117,237 +117,185 @@ def compile(self, student, *, trainset, eval_kwargs): results_best = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} results_latest = {id(p):{"depth": [], "max": [], "average": [], "min":[], "std": []} for p in module.predictors()} - # Define ANSI escape codes for colors - YELLOW = '\033[93m' - BLUE = '\033[94m' - BOLD = '\033[1m' - ENDC = '\033[0m' # Resets the color to default - - random.seed(seed) + if self.track_stats: + import numpy as np + + + candidates = {} + evaluated_candidates = defaultdict(dict) + + # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts + for predictor in module.predictors(): + basic_instruction = None + basic_prefix = None + *_, last_key = self._get_signature(predictor).fields.keys() + basic_instruction = self._get_signature(predictor).instructions + basic_prefix = self._get_signature(predictor).fields[last_key].json_schema_extra['prefix'] + if self.prompt_model: + with dspy.settings.context(lm=self.prompt_model): + instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) + else: + instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) + # Add in our initial prompt as a candidate as well + instruct.completions.proposed_instruction.append(basic_instruction) + instruct.completions.proposed_prefix_for_output_field.append(basic_prefix) + candidates[id(predictor)] = instruct.completions + evaluated_candidates[id(predictor)] = {} - estimated_task_model_calls_wo_module_calls = len(trainset) * num_trials # M * T * P - estimated_prompt_model_calls = 10 + self.num_candidates * len(student.predictors()) # num data summary calls + N * P - - user_message = textwrap.dedent(f"""\ - {YELLOW}{BOLD}WARNING: Projected Language Model (LM) Calls{ENDC} - - Please be advised that based on the parameters you have set, the maximum number of LM calls is projected as follows: - - {YELLOW}- Task Model: {BLUE}{BOLD}{len(trainset)}{ENDC}{YELLOW} examples in dev set * {BLUE}{BOLD}{num_trials}{ENDC}{YELLOW} trials * {BLUE}{BOLD}# of LM calls in your program{ENDC}{YELLOW} = ({BLUE}{BOLD}{estimated_task_model_calls_wo_module_calls} * # of LM calls in your program{ENDC}{YELLOW}) task model calls{ENDC} - {YELLOW}- Prompt Model: # data summarizer calls (max {BLUE}{BOLD}10{ENDC}{YELLOW}) + {BLUE}{BOLD}{self.num_candidates}{ENDC}{YELLOW} * {BLUE}{BOLD}{len(student.predictors())}{ENDC}{YELLOW} lm calls in program = {BLUE}{BOLD}{estimated_prompt_model_calls}{ENDC}{YELLOW} prompt model calls{ENDC} - - {YELLOW}{BOLD}Estimated Cost Calculation:{ENDC} + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - {YELLOW}Total Cost = (Number of calls to task model * (Avg Input Token Length per Call * Task Model Price per Input Token + Avg Output Token Length per Call * Task Model Price per Output Token) - + (Number of calls to prompt model * (Avg Input Token Length per Call * Task Prompt Price per Input Token + Avg Output Token Length per Call * Prompt Model Price per Output Token).{ENDC} - - For a preliminary estimate of potential costs, we recommend you perform your own calculations based on the task - and prompt models you intend to use. If the projected costs exceed your budget or expectations, you may consider: - - {YELLOW}- Reducing the number of trials (`num_trials`), the size of the trainset, or the number of LM calls in your program.{ENDC} - {YELLOW}- Using a cheaper task model to optimize the prompt.{ENDC}""") + latest_candidates = candidates + all_candidates = candidates - user_confirmation_message = textwrap.dedent(f"""\ - To proceed with the execution of this program, please confirm by typing {BLUE}'y'{ENDC} for yes or {BLUE}'n'{ENDC} for no. + module_clone = module.deepcopy() - If you would like to bypass this confirmation step in future executions, set the {YELLOW}`requires_permission_to_run`{ENDC} flag to {YELLOW}`False`.{ENDC} + # For each iteration in depth... + for d in range(self.depth): # TODO: fix this so that we eval the new batch of predictors with the new best followoing predictors + print(f"Iteration Depth: {d+1}/{self.depth}.") - {YELLOW}Awaiting your input...{ENDC} - """) - - print(user_message) + latest_scores = [] - sys.stdout.flush() # Flush the output buffer to force the message to print - - - run=True - if requires_permission_to_run: - print(user_confirmation_message) - user_input = input("Do you wish to continue? (y/n): ").strip().lower() - if user_input != 'y': - print("Compilation aborted by the user.") - run=False - - if run: - if self.track_stats: - import numpy as np - - - candidates = {} - evaluated_candidates = defaultdict(dict) - - # Seed the prompt optimizer zero shot with just the instruction, generate BREADTH new prompts - for predictor in module.predictors(): - basic_instruction = None - basic_prefix = None - *_, last_key = self._get_signature(predictor).fields.keys() - basic_instruction = self._get_signature(predictor).instructions - basic_prefix = self._get_signature(predictor).fields[last_key].json_schema_extra['prefix'] - if self.prompt_model: - with dspy.settings.context(lm=self.prompt_model): - instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) - else: - instruct = dspy.Predict(BasicGenerateInstruction, n=self.breadth-1, temperature=self.init_temperature)(basic_instruction=basic_instruction) - # Add in our initial prompt as a candidate as well - instruct.completions.proposed_instruction.append(basic_instruction) - instruct.completions.proposed_prefix_for_output_field.append(basic_prefix) - candidates[id(predictor)] = instruct.completions - evaluated_candidates[id(predictor)] = {} - - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - - latest_candidates = candidates - all_candidates = candidates - - module_clone = module.deepcopy() - - # For each iteration in depth... - for d in range(self.depth): # TODO: fix this so that we eval the new batch of predictors with the new best followoing predictors - print(f"Iteration Depth: {d+1}/{self.depth}.") - - latest_scores = [] - - # Go through our module's predictors - for p_i, (p_old, p_new) in enumerate(zip(module.predictors(), module_clone.predictors())): - candidates_ = latest_candidates[id(p_old)] # Use the most recently generated candidates for evaluation - if len(module.predictors()) > 1: - candidates_ = all_candidates[id(p_old)] # Unless our program has multiple predictors, in which case we need to reevaluate all prompts with the new prompt(s) for the other predictor(s) - - # For each candidate - for c_i, c in enumerate(candidates_): - # Get the candidate instruction and prefix - instruction, prefix = c.proposed_instruction.strip('"').strip(), c.proposed_prefix_for_output_field.strip('"').strip() - - # Set this new module with our instruction / prefix - *_, last_key = self._get_signature(p_new).fields.keys() - updated_signature = self._get_signature(p_new) \ - .with_instructions(instruction) \ - .with_updated_fields(last_key, prefix=prefix) - self._set_signature(p_new, updated_signature) - - # Score the instruction / prefix - if self.verbose: print("----------------") - for i,predictor in enumerate(module_clone.predictors()): - if self.verbose: print(f"Predictor {i+1}") - self._print_signature(predictor) - print(f"At Depth {d+1}/{self.depth}, Evaluating Prompt Candidate #{c_i+1}/{len(candidates_)} for Predictor {p_i+1} of {len(module.predictors())}.") - score = evaluate(module_clone, devset=trainset, **eval_kwargs) - if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") - total_calls += 1 - if self.verbose: print("----------------") - - replace_entry = True - if self.verbose: print(f"(instruction, prefix) {(instruction, prefix)}") - # if verbose: print(f"evaluated_candidates[id(p_old)] {evaluated_candidates[id(p_old)]}") - if ((instruction, prefix) in evaluated_candidates[id(p_old)]): - # if verbose: print(f"if evaluated_candidates[id(p_old)][(instruction, prefix)] {evaluated_candidates[id(p_old)][(instruction, prefix)]}") - if evaluated_candidates[id(p_old)][(instruction, prefix)]["score"] >= score: - replace_entry = False - - if replace_entry: - # Add it to our evaluated candidates list - evaluated_candidates[id(p_old)][(instruction, prefix)] = { - "score": score, - "program": module_clone.deepcopy(), - "instruction": instruction, - "prefix": prefix, - "depth": d, - } - - if (len(candidates_)-self.breadth <= c_i): - latest_scores.append(score) - - if self.track_stats: - results_latest[id(p_old)]["depth"].append(d) - results_latest[id(p_old)]["max"].append(max(latest_scores)) - results_latest[id(p_old)]["average"].append(sum(latest_scores)/len(latest_scores)) - results_latest[id(p_old)]["min"].append(min(latest_scores)) - results_latest[id(p_old)]["std"].append(np.std(latest_scores)) - - # Now that we've evaluated the candidates, set this predictor to the best performing version - # to ensure the next round of scores reflect the best possible version - best_candidate = max(evaluated_candidates[id(p_old)].values(), key=lambda candidate: candidate['score']) - *_, last_key = self._get_signature(p_old).fields.keys() + # Go through our module's predictors + for p_i, (p_old, p_new) in enumerate(zip(module.predictors(), module_clone.predictors())): + candidates_ = latest_candidates[id(p_old)] # Use the most recently generated candidates for evaluation + if len(module.predictors()) > 1: + candidates_ = all_candidates[id(p_old)] # Unless our program has multiple predictors, in which case we need to reevaluate all prompts with the new prompt(s) for the other predictor(s) + + # For each candidate + for c_i, c in enumerate(candidates_): + # Get the candidate instruction and prefix + instruction, prefix = c.proposed_instruction.strip('"').strip(), c.proposed_prefix_for_output_field.strip('"').strip() + + # Set this new module with our instruction / prefix + *_, last_key = self._get_signature(p_new).fields.keys() updated_signature = self._get_signature(p_new) \ - .with_instructions(best_candidate["instruction"]) \ - .with_updated_fields(last_key, prefix=best_candidate["prefix"]) + .with_instructions(instruction) \ + .with_updated_fields(last_key, prefix=prefix) self._set_signature(p_new, updated_signature) - if self.verbose: print(f"Updating Predictor {id(p_old)} to:\ni: {best_candidate['instruction']}\np: {best_candidate['prefix']}") - if self.verbose: print("Full predictor with update: ") + + # Score the instruction / prefix + if self.verbose: print("----------------") for i,predictor in enumerate(module_clone.predictors()): - if self.verbose: print(f"Predictor {i}") + if self.verbose: print(f"Predictor {i+1}") self._print_signature(predictor) - - if d == self.depth-1: - break - - - new_candidates = {} - for p_base in module.predictors(): - # Build Few-Shot Example of Optimized Prompts - attempts = [] - shortest_len = self.breadth - shortest_len = min(len(evaluated_candidates[id(p_base)]),shortest_len) - best_predictors = list(evaluated_candidates[id(p_base)].values()) - - # best_predictors = evaluated_candidates[id(p_base)].values()[:] - best_predictors.sort(key=lambda x: x['score'], reverse=True) - - if self.track_stats: - scores = [x['score'] for x in best_predictors][:10] - results_best[id(p_base)]["depth"].append(d) - results_best[id(p_base)]["max"].append(max(scores)) - results_best[id(p_base)]["average"].append(sum(scores)/len(scores)) - results_best[id(p_base)]["min"].append(min(scores)) - results_best[id(p_base)]["std"].append(np.std(scores)) + print(f"At Depth {d+1}/{self.depth}, Evaluating Prompt Candidate #{c_i+1}/{len(candidates_)} for Predictor {p_i+1} of {len(module.predictors())}.") + score = evaluate(module_clone, devset=trainset, **eval_kwargs) + if self.verbose and self.prompt_model: print(f"prompt_model.inspect_history(n=1) {self.prompt_model.inspect_history(n=1)}") + total_calls += 1 + if self.verbose: print("----------------") + + replace_entry = True + if self.verbose: print(f"(instruction, prefix) {(instruction, prefix)}") + # if verbose: print(f"evaluated_candidates[id(p_old)] {evaluated_candidates[id(p_old)]}") + if ((instruction, prefix) in evaluated_candidates[id(p_old)]): + # if verbose: print(f"if evaluated_candidates[id(p_old)][(instruction, prefix)] {evaluated_candidates[id(p_old)][(instruction, prefix)]}") + if evaluated_candidates[id(p_old)][(instruction, prefix)]["score"] >= score: + replace_entry = False + + if replace_entry: + # Add it to our evaluated candidates list + evaluated_candidates[id(p_old)][(instruction, prefix)] = { + "score": score, + "program": module_clone.deepcopy(), + "instruction": instruction, + "prefix": prefix, + "depth": d, + } - for i in range(shortest_len-1,-1,-1): - # breakpoint() - attempts.append(f'Instruction #{shortest_len-i}: {best_predictors[i]["instruction"]}') - attempts.append(f'Prefix #{shortest_len-i}: {best_predictors[i]["prefix"]}') - attempts.append(f'Resulting Score #{shortest_len-i}: {best_predictors[i]["score"]}') - - # Generate next batch of potential prompts to optimize, with previous attempts as input - if self.prompt_model: - with dspy.settings.context(lm=self.prompt_model): - instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) - else: - instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) + if (len(candidates_)-self.breadth <= c_i): + latest_scores.append(score) - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - # Get candidates for each predictor - new_candidates[id(p_base)] = instr.completions - all_candidates[id(p_base)].proposed_instruction.extend(instr.completions.proposed_instruction) - all_candidates[id(p_base)].proposed_prefix_for_output_field.extend(instr.completions.proposed_prefix_for_output_field) + if self.track_stats: + results_latest[id(p_old)]["depth"].append(d) + results_latest[id(p_old)]["max"].append(max(latest_scores)) + results_latest[id(p_old)]["average"].append(sum(latest_scores)/len(latest_scores)) + results_latest[id(p_old)]["min"].append(min(latest_scores)) + results_latest[id(p_old)]["std"].append(np.std(latest_scores)) + + # Now that we've evaluated the candidates, set this predictor to the best performing version + # to ensure the next round of scores reflect the best possible version + best_candidate = max(evaluated_candidates[id(p_old)].values(), key=lambda candidate: candidate['score']) + *_, last_key = self._get_signature(p_old).fields.keys() + updated_signature = self._get_signature(p_new) \ + .with_instructions(best_candidate["instruction"]) \ + .with_updated_fields(last_key, prefix=best_candidate["prefix"]) + self._set_signature(p_new, updated_signature) + if self.verbose: print(f"Updating Predictor {id(p_old)} to:\ni: {best_candidate['instruction']}\np: {best_candidate['prefix']}") + if self.verbose: print("Full predictor with update: ") + for i,predictor in enumerate(module_clone.predictors()): + if self.verbose: print(f"Predictor {i}") + self._print_signature(predictor) + + if d == self.depth-1: + break - if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") - latest_candidates = new_candidates - candidates = [] - for predictor in module.predictors(): - candidates.extend(list(evaluated_candidates[id(predictor)].values())) + new_candidates = {} + for p_base in module.predictors(): + # Build Few-Shot Example of Optimized Prompts + attempts = [] + shortest_len = self.breadth + shortest_len = min(len(evaluated_candidates[id(p_base)]),shortest_len) + best_predictors = list(evaluated_candidates[id(p_base)].values()) - if self.track_stats: - best_predictors = list(evaluated_candidates[id(predictor)].values()) - best_predictors.sort(key=lambda x: x['score'], reverse=True) + # best_predictors = evaluated_candidates[id(p_base)].values()[:] + best_predictors.sort(key=lambda x: x['score'], reverse=True) + if self.track_stats: scores = [x['score'] for x in best_predictors][:10] - results_best[id(predictor)]["depth"].append(d) - results_best[id(predictor)]["max"].append(max(scores)) - results_best[id(predictor)]["average"].append(sum(scores)/len(scores)) - results_best[id(predictor)]["min"].append(min(scores)) - results_best[id(predictor)]["std"].append(np.std(scores)) + results_best[id(p_base)]["depth"].append(d) + results_best[id(p_base)]["max"].append(max(scores)) + results_best[id(p_base)]["average"].append(sum(scores)/len(scores)) + results_best[id(p_base)]["min"].append(min(scores)) + results_best[id(p_base)]["std"].append(np.std(scores)) + + for i in range(shortest_len-1,-1,-1): + # breakpoint() + attempts.append(f'Instruction #{shortest_len-i}: {best_predictors[i]["instruction"]}') + attempts.append(f'Prefix #{shortest_len-i}: {best_predictors[i]["prefix"]}') + attempts.append(f'Resulting Score #{shortest_len-i}: {best_predictors[i]["score"]}') + + # Generate next batch of potential prompts to optimize, with previous attempts as input + if self.prompt_model: + with dspy.settings.context(lm=self.prompt_model): + instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) + else: + instr = dspy.Predict(GenerateInstructionGivenAttempts, n=self.breadth, temperature=self.init_temperature)(attempted_instructions=attempts) - # if verbose: print(f"candidates: {candidates}") - candidates.sort(key=lambda x: x['score'], reverse=True) + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + # Get candidates for each predictor + new_candidates[id(p_base)] = instr.completions + all_candidates[id(p_base)].proposed_instruction.extend(instr.completions.proposed_instruction) + all_candidates[id(p_base)].proposed_prefix_for_output_field.extend(instr.completions.proposed_prefix_for_output_field) - candidates = self._drop_duplicates(candidates) + if self.verbose and self.prompt_model: print(f"{self.prompt_model.inspect_history(n=1)}") + latest_candidates = new_candidates + + candidates = [] + for predictor in module.predictors(): + candidates.extend(list(evaluated_candidates[id(predictor)].values())) - best_program = candidates[0]["program"] - best_program.candidate_programs = candidates - best_program.total_calls = total_calls if self.track_stats: - best_program.results_best = results_best - best_program.results_latest = results_latest + best_predictors = list(evaluated_candidates[id(predictor)].values()) + best_predictors.sort(key=lambda x: x['score'], reverse=True) + + scores = [x['score'] for x in best_predictors][:10] + results_best[id(predictor)]["depth"].append(d) + results_best[id(predictor)]["max"].append(max(scores)) + results_best[id(predictor)]["average"].append(sum(scores)/len(scores)) + results_best[id(predictor)]["min"].append(min(scores)) + results_best[id(predictor)]["std"].append(np.std(scores)) + + # if verbose: print(f"candidates: {candidates}") + candidates.sort(key=lambda x: x['score'], reverse=True) + + candidates = self._drop_duplicates(candidates) + + best_program = candidates[0]["program"] + best_program.candidate_programs = candidates + best_program.total_calls = total_calls + if self.track_stats: + best_program.results_best = results_best + best_program.results_latest = results_latest - return best_program \ No newline at end of file + return best_program \ No newline at end of file From 695cefcee02e0d8d2c29b8a0b43634efced6385a Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Fri, 8 Mar 2024 00:19:13 -0800 Subject: [PATCH 40/79] make num_trials a required variable, plus minor changes to notebook --- dspy/teleprompt/mipro_optimizer.py | 4 +- examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb | 61 ++++++++------------ 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/dspy/teleprompt/mipro_optimizer.py b/dspy/teleprompt/mipro_optimizer.py index 3125c562c..c9045ff79 100644 --- a/dspy/teleprompt/mipro_optimizer.py +++ b/dspy/teleprompt/mipro_optimizer.py @@ -103,7 +103,7 @@ class DatasetDescriptorWithPriorObservations(dspy.Signature): observations = dspy.OutputField(desc="Somethings that holds true for most or all of the data you observed or COMPLETE if you have nothing to add") class MIPRO(Teleprompter): - def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, num_candidates=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): + def __init__(self, metric, prompt_model=None, task_model=None, teacher_settings={}, num_candidates=10, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): self.num_candidates = num_candidates self.metric = metric self.init_temperature = init_temperature @@ -275,7 +275,7 @@ def _generate_first_N_candidates(self, module, N, view_data, view_examples, demo return candidates, evaluated_candidates - def compile(self, student, *, trainset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True, num_trials=None): + def compile(self, student, *, trainset, num_trials, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, view_data=True, view_examples=True, requires_permission_to_run=True): # Define ANSI escape codes for colors YELLOW = '\033[93m' BLUE = '\033[94m' diff --git a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb index e50831c93..964c6329c 100644 --- a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb +++ b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb @@ -66,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -74,7 +74,16 @@ "id": "JpijP_d7qZH2", "outputId": "422dc4d0-4574-4e4b-935a-c7b4c875472f" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], "source": [ "%load_ext autoreload\n", "%autoreload 2\n", @@ -117,7 +126,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -175,7 +184,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 12, "metadata": { "id": "UHWzGRVgqZH2" }, @@ -219,7 +228,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -420,7 +429,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 14, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -433,14 +442,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 0 / 2 (0.0): 0%| | 1/500 [00:00<03:17, 2.52it/s]" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 80 / 500 (16.0): 100%|██████████| 500/500 [00:33<00:00, 15.10it/s]\n", + "Average Metric: 80 / 500 (16.0): 100%|██████████| 500/500 [00:30<00:00, 16.16it/s]\n", "/lfs/0/kristaoo/dspy/dspy/evaluate/evaluate.py:187: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n", " df = df.applymap(truncate_cell)\n" ] @@ -456,7 +458,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 107 / 500 (21.4): 100%|██████████| 500/500 [00:32<00:00, 15.31it/s]" + "Average Metric: 107 / 500 (21.4): 100%|██████████| 500/500 [00:30<00:00, 16.50it/s]\n" ] }, { @@ -465,13 +467,6 @@ "text": [ "Average Metric: 107 / 500 (21.4%)\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n" - ] } ], "source": [ @@ -515,7 +510,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 15, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -523,15 +518,7 @@ "id": "TpFW7IaYqZH3", "outputId": "b83c427f-953d-4fa7-b19c-03704369ab53" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/lfs/0/kristaoo/dspy/examples/qa/hotpot/MIPRO_notebook_cache/compiler\n" - ] - } - ], + "outputs": [], "source": [ "import cloudpickle as pickle\n", "from dspy.teleprompt import MIPRO\n", @@ -569,7 +556,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 16, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -582,7 +569,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 192 / 500 (38.4): 100%|██████████| 500/500 [00:30<00:00, 16.24it/s]\n" + "Average Metric: 192 / 500 (38.4): 100%|██████████| 500/500 [00:30<00:00, 16.19it/s]\n" ] }, { @@ -596,7 +583,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 193 / 500 (38.6): 100%|██████████| 500/500 [00:32<00:00, 15.53it/s]\n" + "Average Metric: 193 / 500 (38.6): 100%|██████████| 500/500 [00:30<00:00, 16.22it/s]\n" ] }, { @@ -632,7 +619,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 17, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -692,7 +679,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 18, "metadata": { "colab": { "base_uri": "https://localhost:8080/" From d2a2f8994499c110b81d71d54beadd18506732e1 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Fri, 8 Mar 2024 00:49:14 -0800 Subject: [PATCH 41/79] adding notebook cache_dir in front of dspy import --- examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb | 3011 +++++++----------- 1 file changed, 1142 insertions(+), 1869 deletions(-) diff --git a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb index 964c6329c..d0f9e4a49 100644 --- a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb +++ b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb @@ -61,29 +61,20 @@ "id": "5Vo4Tb9srSow" }, "source": [ - "First, we will install __DSPy__ if it's not there already." + "First, we will install __DSPy__ if it's not there already. We'll also __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook. We'll also load in our pre optimized program from hugging face to inspect later." ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "JpijP_d7qZH2", - "outputId": "422dc4d0-4574-4e4b-935a-c7b4c875472f" + "outputId": "c641a4b1-05f5-45cc-d715-4347c526b576" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The autoreload extension is already loaded. To reload it, use:\n", - " %reload_ext autoreload\n" - ] - } - ], + "outputs": [], "source": [ "%load_ext autoreload\n", "%autoreload 2\n", @@ -112,55 +103,6 @@ " !pip install -e $repo_path\n", " !pip install --upgrade cloudpickle==3.0.0\n", "\n", - "import dspy" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "rbGIXWcqqZH1" - }, - "source": [ - "Then, we'll __load in the cached requests__ for this tasks, so that we don't actually need to call any LMs for this notebook. We'll also load in our pre optimized program from hugging face to inspect later." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 205, - "referenced_widgets": [ - "827d6f08a1894525937562b64df50dc6", - "c977f3fcb63349b294414c28e6bb17d3", - "9f2a85011d284134bced1a72e0f13d9c", - "435b0b18054e454eac41b3722cbe0400", - "b563cc49cf3341f8a54ab0183e8a9794", - "b2c1beb7364a43288209f5e5a6ad2514", - "e338d68fb7694b85bc573c0df83fa23e", - "6fcb23a0eb444b88a1cef94740551fe8", - "35a4261bb9494f068b4e5f2cbe9a927a", - "0cb7129e44b04ef88154a8a32b025391", - "63b53c83345841b69b06b71b830e9adf", - "aa4f1d66d377449c8cb4a73056138d50", - "54f904d1274c499ca7e714fa8cdf6d61", - "2efe34e3d66b4b64b4552d278d4a5962", - "a9c39bc2e1804ad399f1dc66d192df46", - "d04e9ed9ccb64b17903e10e749d097a7", - "abec858558814b2b809cd318aaac1545", - "ce54414ed74441478f593ae366ff16b4", - "fcd8aef3637c4449bef71809764642c2", - "e716458e84c14cb7948ab6dc61f337b9", - "4c081aaabbdb448b91fead4fa73f6c0b", - "da0f46c68b0141a48c887faa0843d5ab" - ] - }, - "id": "l4Fsh7EhqZH1", - "outputId": "5fea0db6-8cb1-4485-91f7-bc1e7dfe5d4b" - }, - "outputs": [], - "source": [ "from huggingface_hub import hf_hub_download\n", "import zipfile\n", "import os\n", @@ -170,7 +112,9 @@ "compiled_program_file_path = hf_hub_download(repo_id=repo_id, filename='compiled_program.pickle')\n", "with zipfile.ZipFile(cache_file_path, 'r') as zip_ref:\n", " zip_ref.extractall(\".\")\n", - "os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = f\"{os.getcwd()}/MIPRO_notebook_cache\"" + "os.environ[\"DSP_NOTEBOOK_CACHEDIR\"] = f\"{os.getcwd()}/MIPRO_notebook_cache\"\n", + "\n", + "import dspy" ] }, { @@ -184,14 +128,15 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 2, "metadata": { "id": "UHWzGRVgqZH2" }, "outputs": [], "source": [ + "import openai\n", + "\n", "### NOTE: if you'd like to run this code without a cache, you can remove these lines to configure your OPEN AI key ###\n", - "# import openai\n", "# os.environ['OPENAI_API_KEY'] = \"TODO: ADD YOUR OPEN AI KEY HERE\"\n", "# openai.api_key = os.environ.get('OPENAI_API_KEY')\n", "# openai.api_base = \"https://api.openai.com/v1\"\n", @@ -228,115 +173,115 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 340, "referenced_widgets": [ - "fb0bb0cd51d24f7a9ea4bc5acdab0b6f", - "4cd600dc92fa4dcbb1f6878dfc951a84", - "2d9675dfff7244e3a2c4273e6beac742", - "ebb8d03b2088443988427c674f2ebd08", - "bb649fd497164542865182285391c1cb", - "0ce5aafe3feb4e30b154e8feee246680", - "292a903dd61540beb28f0dcc33e60173", - "4c10718ba99243a795348fffc0317d89", - "47ba7929b5a3483bad6dba45b3839d28", - "d50c0b7e0f35439c938bee5d2159ff82", - "c8da2fa4b14e43948824f527e9665354", - "02b66439b0d3463c835f54ee43a81b29", - "757ec3ba99bc49b78386be420b315738", - "14f1e99c941349ceabc1d360deb1a14d", - "d601031bf4744c849885f7becf1e5f76", - "2ac62fd2e5d64e44a69551d27913caf8", - "a6a9ecf3b2d74a1ab78a904f76b462c7", - "0fcf2dc801ac414ca7ff9db0790e322c", - "b2b11f62717f482a8c7d28dfef7282e0", - "ffda68bae3e34d39abce4d2064b88617", - "0083f3cd53b742a6916f9131bffc92ab", - "85c4f1c241054d989d893130ca7ec595", - "ef2f0db8dc4148daae63001d4c6a555b", - "2f24b6572cb44cbaac147b28a4490582", - "83926bd6a50441959fdc945808cbea61", - "a93f7fced2444026bed86ff3ac73ab46", - "b7d6568fa80446e1a9ca2f9102b47f7f", - "f66e4271b9544b83b598700cc97593e9", - "530d6c38c848425082f506709fecb5f7", - "e035507b6408448f87ca0fee35bc1bb1", - "42d3de61644547ad80e585629fd97c3d", - "978d5cab723f4f02bcadb71b099840a8", - "05f74ff1c66d41858e4436707089ce10", - "67dd858331754b7a944bd9cb725c5409", - "9b318e36701f43a38bf49db28f1f82d6", - "5859289715b94e09b45bb2215fd8f663", - "4ffa164e576e43788118a2574ae6089b", - "c066cdb020ff4d0f925def7eb9373228", - "48b4d8350a074defb044eeaa9586f9c0", - "b8924c8accbc415e8e28bc232d063003", - "a2b761c3ce72458a8ef3d47903d42828", - "6bd216ee356e4853ac52c81f5632834d", - "053a5c1ad4cd47548a8a358dc8834c50", - "338ffb9834b44e0b9a9a353ede75f9d6", - "3ec77a173a5345fcb06827a87b4ddf38", - "c47e844caea446e1a452426ed899fe36", - "060cbe0e37dc422591916d3768066224", - "e68714c12f8543c9b14360f8f1d37604", - "bfdbc53eb3d34077bbfa0f8806733704", - "7038244ae993489eb76422d4f6135e58", - "76a9b3ae6fdb4ee2a228966556287752", - "13ee127ea31847b9b3d5f6a8a0b10cfa", - "f99a2f9616c744578b88fb1322674c32", - "43d07caba731495f9fe22a7ef81ef19a", - "2532bb223c2d4dbeb2cfeffbfdeac65b", - "cd15509869ed4a518b6d4d48b932e314", - "2ab35b29510c422ca4f07bfad4339419", - "bba71ee322f548439853954f1c055977", - "cb6ef0a279774d1f81cf2f4efb3b3c04", - "eca4539630b04bb2b927d780ef4ca849", - "bdd29de7feba4156823b10124217ef54", - "63742b8642ae4a94999bd5cdb3fa7da2", - "6aec8a01051743acab8de920672cf38f", - "0576fd9cffb4489fa07c4af347ada10e", - "e8e84a2a7343409d8f81439a42e53601", - "f13ff2cfe1a6443296cd1a9fe956312e", - "371665875b63442586198c64f3f441dc", - "4dc0cc26e04741c1b9a28deb1c0f533d", - "c95c3c713b9c4e7b95ab273b17c20788", - "176abb1c80904828965774b9c5ed2558", - "10cf746afb1b4c748ce5fda0dd026ab9", - "67d3a00c8e9e4e9a81a039e8b05c1200", - "b27566e9133a493bbba2af2f1cd1118c", - "ebb50f6701c146efafef65ab75cb5901", - "8dbde39ea3c144268b2547c55863c929", - "70c258c2634b431cb283420f86675818", - "88f9b45c9508415fb29fe786768be085", - "1f5f6e14543a4fe48f90459afe074739", - "823a30d9f3f34793b8eb8b79899eaf19", - "bb56dc209d8646ec84b3d194761c1e57", - "30d9db28931442a0b15ef29792e0a6a9", - "cbe4ee8e8d5646b98f4ff470952384da", - "52747a49054d454e8f899fc832985877", - "1af61e78281347429396163cdae419ed", - "f30e71e4d77c43d7b8b45ff9b3905d51", - "90a8e892d747436aa02bce59454b117d", - "ad62117365344dfbbed1fd46ae8238e6", - "a2454d2f78b34a279e8cad724200d5eb", - "ae83b2e7628e4345896eba886b563bc3", - "560375a7cc364b65be6f72db30139ce3", - "8c0bf6da280e4db88b24b2e1028f9841", - "44ed3f5af4234059b806dcc26abb99c7", - "dd09c11a454b4edb81f18e018dc917ca", - "56ac79bb987146c7ba76f1bd0315360f", - "e2e51fbcedad401ba7d79ac45258a3df", - "97e73f6600c641fd9e724d992a8b8d6d", - "68d13e7ab60245f9910806508ae08cc0", - "571bcef58c3440ce9aa9cb4f441ec97a", - "d2f1105f250542649c0b6cb4c27d75df" + "e16044d880174c49af557bd12789493f", + "531c380db44a404ebb168648ea77c3f4", + "e8a46c6ac8a54fdbb44b2c8914552e64", + "81cbe1842465400cba02a46309d98064", + "f8ada809ecdb417ebc8214d860dd6552", + "74d58314b1c449e0b7dec3bda8b653c2", + "8b7b2b9489ae49049befae848d0fb1a1", + "2d47a6a66054438d8e9a3c5e5767c056", + "3b57d0a9768f4befb7509581289035ad", + "134fa83980e142bf82d5b97cfc10da69", + "35e4e99036894a2ba37d9ba23581a8ff", + "835a1e675186490692e336da943d635d", + "95bcef02eb794979b7873b81021e4b40", + "d84324c4c3dc40fea04cc0df1539b4d8", + "a6213bcdbcb24b1694204e6baeb763d8", + "bc423d0878154adf940062660a8315ad", + "0a1744c363f640b5b8939f32f6e72922", + "bbd2db64988147f1a4f8856d890bb4c7", + "ba2b4d7ecdbc4512acf180d8a0d602e8", + "1bb155669e2a441d8992030e8aaa84a9", + "43ed7af1d9c84ac8a6ec2195e48e60eb", + "ac6822762e6b46bd862d6f923aeb4437", + "348bb4fff900492cba8333156626a947", + "697eaeb1a004493a9260a3a89671a9ca", + "8a64950ea896468da3d10f46e9718ec8", + "7b0b45020d0f45288e2f0e4ceff22524", + "ad21e20d1f1b4b6ea74fdab03af8acdb", + "1aab1d48c6124526bee6c74892ecd953", + "598c6f37331e448889b175393a00deff", + "20d8df0ee0a4442582686846757bcc7f", + "fa4e50aaf53d4edfb9ca3046cbada2db", + "96ad4454539145aea6549995344160e3", + "acc3573e48f14dffb635f8632c6f6e74", + "6c0432c6cd8f4cae9aeb8c2870b39922", + "99b8f3882032404990f2b453111a63ba", + "6c21df0657ce486381ba2310c7fa0029", + "a20ac344a32340c785cd162fd0eb55b5", + "6ba50c3ec9e542d5a8d2f900fbcb8689", + "a298045042014c88939a9fe785fccda8", + "84bed63c6597486ca6c39b9c0c4d20bd", + "2a75d45acfb44463af974acb7a1b0d8e", + "ae814b8e55454e0aadc48f7e595575ee", + "ff4bcec9c18e4f04b1f7898daaffeb1a", + "e9c64a790d684c9eaf7f49eea003f43c", + "52f1714412df4ec78f6ff7d0f8a69862", + "988055b44cf9411e8d45d8a4185fef07", + "59be08d44c824d76b8525df14191d569", + "6fde64f36dd84d8eae670efe95e2313a", + "66e6502a463145daa440e967d8bdfdca", + "29cab51fec0b4dacaa8f829ff217c839", + "6ecbf23579324112981d4bce0c0ce369", + "a105ef4f1f754c44b7bc0ec8edf0c0cc", + "1c7d71e42c8c494f867b30d781beb681", + "2f1e652cfa514054abfda794bdfa61a5", + "b17f4731e8e44858889114c52b8f3dd4", + "d50f5eafe90c4684bbdd96569b8ff247", + "9f07fa213de247dabcd3f4213d35a97e", + "782af098d37d4543a4a01ecfed4e5da2", + "037b10adf9724e058c6468f4ca74ed86", + "c7d10443100e49d28266aef9f644ed47", + "d6a78aabcca74314a5b4bb98f350693a", + "954f3cfcb5d44dddbf1d4db9e99c0d70", + "62d8196169bb4a76a94c16d6f1ca61a6", + "0a16c7f37b9a4bbe9bfe7e737ea62801", + "942897aa22214745adee56d2c54447e9", + "0b49910850f3445abe63b6bc7ac18412", + "12a9763cd97742f4ab80c0494a398ca6", + "9d4f14862b704d9bb53d9e74365d14ac", + "56989c76e1534cfd8c9b0da93b3b8bf8", + "f120c447645446e4a04791b97ce9ae93", + "6a5d5ea44c0d4e4384b8956b48c34f14", + "e3dd508496f44171b0d91aca0e8b16a5", + "dc8077859eec4261a28d708ab06a1008", + "9a733957f8fc446fbde053ba87289c71", + "287c9f993cd44039923fdc122cd9e040", + "5cfebfd6308349038f9cd7ad5bc00fe5", + "56b80fc45dd247deadceffe17557f0f9", + "7d80528c4b1c48318756230b0174923c", + "398d7d36bbd041fe81ec633e973fc504", + "d01ca0dd46ee4a4daeeee92214bc07d1", + "6028a5e08f8641f5b8e8182e50f55419", + "567646442eb940b09456328d49248945", + "41961130caaf4537a4c1793574c785d7", + "e9935b60c48d46469904492e20f9c2e8", + "f048b50740e94bd8805c142eac1673b6", + "a5effa5d67534fb4be2e3320c1fb2b9f", + "09b3f2c456af41cba9264dbb9a724027", + "e2f3a3377ad64a4cb9f3a42c1ac97344", + "8e396041a4fd4e6db02410a09b7556c7", + "4cd1dc71c80b401da19ed52ef5148d60", + "1f23a95e292249a19055f70cda2622a3", + "69412c7605ec48859baef6f31c91c520", + "ee64a46b61454949ade4177c059bcf61", + "de6507e9f45741218bf31a9af728b2bf", + "38abb8f460d24c27a66c54bb0417f8ce", + "33267de625db44c2a63d7c7d412a7e61", + "19fe27a0df5a4d39873dd1031904405c", + "dba7ce7c756d468b94d0bc8f4815ab6f", + "926cbb119ea745cf9e344c0e50b75f62" ] }, "id": "hiVgd3N7qZH3", - "outputId": "8b0ef2cf-1836-4aab-8990-62aa6240ab1f" + "outputId": "81b97d83-7c5f-4763-d104-3ad320425a2a" }, "outputs": [ { @@ -429,20 +374,27 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 4, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "MU2aHQBTqZH3", - "outputId": "32f26cb9-2e6d-48b7-9732-9f3c5b60ef7a" + "outputId": "786ba2f2-ae0a-4c68-b602-d601fb5a5aa5" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 80 / 500 (16.0): 100%|██████████| 500/500 [00:30<00:00, 16.16it/s]\n", + "Average Metric: 3 / 7 (42.9): 1%| | 6/500 [00:00<00:43, 11.48it/s]" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 108 / 500 (21.6): 100%|██████████| 500/500 [00:33<00:00, 14.99it/s]\n", "/lfs/0/kristaoo/dspy/dspy/evaluate/evaluate.py:187: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n", " df = df.applymap(truncate_cell)\n" ] @@ -451,21 +403,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "Average Metric: 80 / 500 (16.0%)\n" + "Average Metric: 108 / 500 (21.6%)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 107 / 500 (21.4): 100%|██████████| 500/500 [00:30<00:00, 16.50it/s]\n" + "Average Metric: 113 / 500 (22.6): 100%|██████████| 500/500 [00:33<00:00, 14.78it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Average Metric: 107 / 500 (21.4%)\n" + "Average Metric: 113 / 500 (22.6%)\n" ] } ], @@ -510,15 +462,19 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 5, "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "TpFW7IaYqZH3", - "outputId": "b83c427f-953d-4fa7-b19c-03704369ab53" + "id": "NVfMJ_FpBlSI" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/lfs/0/kristaoo/dspy/examples/qa/hotpot/MIPRO_notebook_cache/compiler\n" + ] + } + ], "source": [ "import cloudpickle as pickle\n", "from dspy.teleprompt import MIPRO\n", @@ -556,41 +512,51 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 6, "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "VvnBp7huqZH3", - "outputId": "b9752a09-1d8b-4225-cc29-21b32a831eea" + "id": "VvnBp7huqZH3" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Average Metric: 192 / 500 (38.4): 100%|██████████| 500/500 [00:30<00:00, 16.19it/s]\n" + " 0%| | 0/500 [00:00 Date: Fri, 8 Mar 2024 00:58:39 -0800 Subject: [PATCH 42/79] removing re import from notebook --- examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb index d0f9e4a49..3909acb7f 100644 --- a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb +++ b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb @@ -81,7 +81,6 @@ "\n", "import sys\n", "import os\n", - "import regex as re\n", "\n", "try: # When on google Colab, let's clone the notebook so we download the cache.\n", " import google.colab\n", From 48663a2327b082b17526a8b7c0bd13714b397e98 Mon Sep 17 00:00:00 2001 From: domci Date: Fri, 8 Mar 2024 13:35:38 +0100 Subject: [PATCH 43/79] feature(dspy): added Metadata for ChromaDB retrieval --- dspy/retrieve/chromadb_rm.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dspy/retrieve/chromadb_rm.py b/dspy/retrieve/chromadb_rm.py index 07ef407d1..e8a892ea1 100644 --- a/dspy/retrieve/chromadb_rm.py +++ b/dspy/retrieve/chromadb_rm.py @@ -145,6 +145,10 @@ def forward( query_embeddings=embeddings, n_results=k, ) - passages = [dotdict({"long_text": x}) for x in results["documents"][0]] - - return passages + zipped_results = zip( + results["ids"][0], + results["distances"][0], + results["documents"][0], + results["metadatas"][0]) + results = [dotdict({"id": id, "score": dist, "long_text": doc, "metadatas": meta }) for id, dist, doc, meta in zipped_results] + return results From 1d090ebe6c47b09f2d1f413e2ae70d788f37ca26 Mon Sep 17 00:00:00 2001 From: Omar Khattab Date: Fri, 8 Mar 2024 07:43:59 -0800 Subject: [PATCH 44/79] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3f3bb1858..b98fe0807 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="dspy-ai", - version="2.3.6", + version="2.3.7", description="DSPy", long_description=long_description, long_description_content_type='text/markdown', From 75f9d252b26ba7ae15447099aabd7468a18a9a4f Mon Sep 17 00:00:00 2001 From: Omar Khattab Date: Fri, 8 Mar 2024 07:44:14 -0800 Subject: [PATCH 45/79] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7d4c7b563..e93f4b823 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "dspy-ai" -version = "2.3.6" +version = "2.3.7" description = "DSPy" readme = "README.md" authors = [{ name = "Omar Khattab", email = "okhattab@stanford.edu" }] From df992444d7630ec5ea6176d4ae6438122008c27f Mon Sep 17 00:00:00 2001 From: Omar Khattab Date: Fri, 8 Mar 2024 08:06:17 -0800 Subject: [PATCH 46/79] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b98fe0807..437589758 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="dspy-ai", - version="2.3.7", + version="2.4.0", description="DSPy", long_description=long_description, long_description_content_type='text/markdown', From f03ba08daaac369ab2e103713f50f0d71fb7bd21 Mon Sep 17 00:00:00 2001 From: Omar Khattab Date: Fri, 8 Mar 2024 08:06:35 -0800 Subject: [PATCH 47/79] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e93f4b823..689a27ec4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "dspy-ai" -version = "2.3.7" +version = "2.4.0" description = "DSPy" readme = "README.md" authors = [{ name = "Omar Khattab", email = "okhattab@stanford.edu" }] From fbef3051ba24ddd3711176dab964f9e829e98c39 Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Fri, 8 Mar 2024 09:26:22 -0800 Subject: [PATCH 48/79] fix to signature optimizer - setting num_candidates --- dspy/teleprompt/signature_opt_bayesian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index 5d009f86e..b74c96151 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -39,7 +39,7 @@ class BayesianSignatureOptimizer(MIPRO): def __init__(self, prompt_model=None, task_model=None, teacher_settings={}, n=10, metric=None, init_temperature=1.0, verbose=False, track_stats=True, view_data_batch_size=10): print("\u001b[31m[WARNING] BayesianSignatureOptimizer has been deprecated and replaced with MIPRO. BayesianSignatureOptimizer will be removed in a future release. \u001b[31m") - super().__init__(prompt_model, task_model, teacher_settings,n,metric,init_temperature,verbose,track_stats,view_data_batch_size) + super().__init__(metric=metric,prompt_model=prompt_model, task_model=task_model, teacher_settings=teacher_settings,num_candidates=n,init_temperature=init_temperature,verbose=verbose,track_stats=track_stats,view_data_batch_size=view_data_batch_size) def compile(self, student, *, devset, max_bootstrapped_demos, max_labeled_demos, eval_kwargs, seed=42, optuna_trials_num, view_data=True, view_examples=True, requires_permission_to_run=False, num_trials=None): return super().compile(student, trainset=devset, max_bootstrapped_demos=max_bootstrapped_demos, max_labeled_demos=max_labeled_demos, eval_kwargs=eval_kwargs, seed=seed, view_data=view_data, view_examples=view_examples, requires_permission_to_run=requires_permission_to_run, num_trials=optuna_trials_num) From 0c48d8652efe23a49f2616e4f20b6b4c01bca8ff Mon Sep 17 00:00:00 2001 From: Omar Khattab Date: Fri, 8 Mar 2024 09:32:24 -0800 Subject: [PATCH 49/79] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 437589758..db9e1f8e4 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="dspy-ai", - version="2.4.0", + version="2.4.1", description="DSPy", long_description=long_description, long_description_content_type='text/markdown', From 0456b51eb60d12f952466e18e27b89c847d62f35 Mon Sep 17 00:00:00 2001 From: Omar Khattab Date: Fri, 8 Mar 2024 09:33:05 -0800 Subject: [PATCH 50/79] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 689a27ec4..adc6f2036 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "dspy-ai" -version = "2.4.0" +version = "2.4.1" description = "DSPy" readme = "README.md" authors = [{ name = "Omar Khattab", email = "okhattab@stanford.edu" }] From 167a13321dcf778048b93c73daa31639722ae18c Mon Sep 17 00:00:00 2001 From: klopsahlong Date: Fri, 8 Mar 2024 10:11:38 -0800 Subject: [PATCH 51/79] adding in colab badge --- examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb index 3909acb7f..a863e0e96 100644 --- a/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb +++ b/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb @@ -15,7 +15,8 @@ "id": "3wEDck3ZqZH0" }, "source": [ - "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy" + "# Using __Multi-stage Instruction Proposal & Optimization (MIPRO)__ in DSPy\n", + "[![colab-badge](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/stanfordnlp/dspy/blob/main/examples/qa/hotpot/hotpotqa_with_MIPRO.ipynb)" ] }, { From 5d3c2c41ae5ce8b597541c9854f5b6c54f028283 Mon Sep 17 00:00:00 2001 From: Herumb Shandilya Date: Sat, 9 Mar 2024 00:15:16 +0530 Subject: [PATCH 52/79] Adding typed predictor docs --- docs/api/functional/dspy_cot.md | 4 - docs/docs/building-blocks/7-assertions.md | 1 + .../building-blocks/8-typed_predictors.md | 159 +++++++++++++++++- .../language_model_clients/_category_.json | 2 +- .../retrieval_models_clients/_category_.json | 2 +- .../deep-dive/teleprompter/_category_.json | 2 +- .../typed_predictors/_category_.json | 8 + 7 files changed, 167 insertions(+), 11 deletions(-) diff --git a/docs/api/functional/dspy_cot.md b/docs/api/functional/dspy_cot.md index 9b9e3bbea..73c140f8f 100644 --- a/docs/api/functional/dspy_cot.md +++ b/docs/api/functional/dspy_cot.md @@ -2,10 +2,6 @@ sidebar_position: 4 --- ---- -sidebar_position: 3 ---- - # dspy.cot ### Overview diff --git a/docs/docs/building-blocks/7-assertions.md b/docs/docs/building-blocks/7-assertions.md index c8b5acc06..71ad16313 100644 --- a/docs/docs/building-blocks/7-assertions.md +++ b/docs/docs/building-blocks/7-assertions.md @@ -1,4 +1,5 @@ # DSPy Assertions + ## Introduction Language models (LMs) have transformed how we interact with machine learning, offering vast capabilities in natural language understanding and generation. However, ensuring these models adhere to domain-specific constraints remains a challenge. Despite the growth of techniques like fine-tuning or “prompt engineering”, these approaches are extremely tedious and rely on heavy, manual hand-waving to guide the LMs in adhering to specific constraints. Even DSPy's modularity of programming prompting pipelines lacks mechanisms to effectively and automatically enforce these constraints. diff --git a/docs/docs/building-blocks/8-typed_predictors.md b/docs/docs/building-blocks/8-typed_predictors.md index 65032474b..874fa29be 100644 --- a/docs/docs/building-blocks/8-typed_predictors.md +++ b/docs/docs/building-blocks/8-typed_predictors.md @@ -1,13 +1,164 @@ # Typed Predictors -In DSPy, alongside Signatures a +In DSPy Signatures, we have `InputField` and `OutputField` that define the nature of inputs and outputs of the field. However the inputs and output to these fields is always string, you can seperately process these inputs and outputs in complicated scenarios but the inherent type is always `str`. + +Pydantic `BaseModel` is a great way to enforce type constraints on the fields, but it is not directly compatible with the `dspy.Signature`. This is where Typed Predictors come in. They are a way to enforce the type constraints on the inputs and outputs of the fields in a `dspy.Signature`. ## Executing Typed Predictors -## Chain of Thoughts with Typed Predictors +Using Typed Predictors is not too different than any other module, infact aside from adding type hints to signature attributes and using a special Predictor module instead of `dspy.Predict` there is nothing else to do. Let's take a look at a simple example to understand this. + +### Defining Input and Output Models + +Let's take an simple task as example i.e. given the `context` and `query` the LLM should give me an `answer` and `confidence_score`. The task could be modelled better but this is just for illustration purposes. Let's define our `Input` and `Output` models via pydantic. + +```python +from pydantic import BaseModel, Field + +class Input(BaseModel): + context: str = Field(..., description="The context for the question") + query: str = Field(..., description="The question to be answered") + +class Output(BaseModel): + answer: str = Field(..., description="The answer for the question") + factual_: float = Field(..., description="The confidence score for the answer") +``` + +As you can see this is where you can provide description to the attributes now. Now that we have the input and output models, let's define a simple Signature that takes in the input and returns the output. + +### Creating Typed Predictor + +A Typed Predictor needs a Typed Signature which is not any different than a normal `dspy.Signature` everything is the same except here you provide type of each field as well. + +```python +class QASignature(dspy.Signature): + """Answer the question based on the context and query provided, and on the scale of 10 tell how confident you are about the answer.""" + + input: Input = dspy.InputField() + output: Output = dspy.OutputField() +``` + +Now that we have the `QASignature`, let's define a Typed Predictor that let's use execute this Signature while conforming to the type constraints. + +```python +predictor = dspy.TypedPredictor(QASignature) +``` + +Just how we pass the Signature to other modules we pass the `QASignature` to `dspy.TypedPredictor`, where typed constraints are inforced. + +### I/O in Typed Predictors + +Now that we have the Typed Predictor let's test it out by providing some sample input to the predictor and see the output and it's type. We can create a `Input` instance and pass it to the predictor to get a dictionary of the output. + +```python +doc_query_pair = Input( + context="The quick brown fox jumps over the lazy dog", + query="What does the fox jumps over?", +) + +prediction = predictor(input=doc_query_pair) +``` + +Now that we have the prediction, we can see the output and it's type. + +```python +answer = prediction['answer'] +confidence_score = prediction['confidence_score'] + +print(f"Prediction: {prediction}\n\n") +print(f"Answer: {answer}, Answer Type: {type(answer)}") +print(f"Confidence Score: {confidence_score}, Confidence Score Type: {type(confidence_score)}") +``` + +## Typed Chain of Thoughts with `dspy.TypedChainOfThought` + +If `TypedPredictor` is the typed counterpart of `dspy.Predict` then `TypedChainOfThought` is the typed counterpart of `dspy.ChainOfThought`. It adds a Chain of Thoughts `dspy.OutputField` to the `dspy.TypedPredictor` module by prepending it to the Signature. + +```python +cot_predictor = dspy.TypedChainOfThought(QASignature) + +doc_query_pair = Input( + context="The quick brown fox jumps over the lazy dog", + query="What does the fox jumps over?", +) + +prediction = cot_predictor(input=doc_query_pair) +``` + +## Typed Predictors as Decorators + +While the `dspy.TypedPredictor` and `dspy.TypedChainOfThought` provide a convinient way to use typed predictors, you can also use their as decorators to enforce type constraints on the inputs and outputs of the function. Good thing is that you won't need to explicitly define a Signature class because it's created internally based on function arguments, outputs and docstring. + +``` +# Function name is output key + +@dspy.predictor +def qa_function(doc_query_pair: Input) -> Output: + """Answer the question based on the context and query provided, and on the scale of 10 tell how confident you are about the answer.""" + pass + +@dspy.cot +def qa_function(doc_query_pair: Input) -> Output: + """Answer the question based on the context and query provided, and on the scale of 10 tell how confident you are about the answer.""" + pass +``` + +## Composing Functional Typed Predictors in `dspy.Module` + +If you're creating DSPy pipelines via `dspy.Module` then you can simply use Functional Typed Predictors by creating these class methods and using them as decorators. Here is an example of using functional typed predictors to create a `SimplifiedBaleen` pipeline: + +```python +class SimplifiedBaleen(FunctionalModule): + def __init__(self, passages_per_hop=3, max_hops=1): + super().__init__() + self.retrieve = dspy.Retrieve(k=passages_per_hop) + self.max_hops = max_hops + + @cot + def generate_query(self, context: list[str], question) -> str: + """Write a simple search query that will help answer a complex question.""" + pass + + @cot + def generate_answer(self, context: list[str], question) -> str: + """Answer questions with short factoid answers.""" + pass + + def forward(self, question): + context = [] + + for _ in range(self.max_hops): + query = self.generate_query(context=context, question=question) + passages = self.retrieve(query).passages + context = deduplicate(context + passages) + + answer = self.generate_answer(context=context, question=question) + return dspy.Prediction(context=context, answer=answer) +``` ## Optimizing Typed Predictors -## Typed Predictors via Decorators +Typed predictors can be optimized using `optimize_signature` optimizer which optimizes the instructions of the Signature. Here is an example of using `optimize_signature` to optimize the `QASignature`: + +```python +import dspy +from dspy.evaluate import Evaluate +from dspy.evaluate.metrics import answer_exact_match +from dspy.teleprompt.signature_opt_typed import optimize_signature + +turbo = dspy.OpenAI(model='gpt-3.5-turbo', max_tokens=4000) +gpt4 = dspy.OpenAI(model='gpt-4', max_tokens=4000) +dspy.settings.configure(lm=turbo) + +evaluator = Evaluate(devset=devset, metric=answer_exact_match, num_threads=10, display_progress=True) -## Composing Functional Typed Predictors in `dspy.Module` \ No newline at end of file +result = optimize_signature( + student=dspy.TypedPredictor(QASignature), + evaluator=evaluator, + initial_prompts=6, + n_iterations=100, + max_examples=30, + verbose=True, + prompt_model=gpt4, +) +``` \ No newline at end of file diff --git a/docs/docs/deep-dive/language_model_clients/_category_.json b/docs/docs/deep-dive/language_model_clients/_category_.json index ccd8f3122..6fe54c326 100644 --- a/docs/docs/deep-dive/language_model_clients/_category_.json +++ b/docs/docs/deep-dive/language_model_clients/_category_.json @@ -1,6 +1,6 @@ { "label": "Language Model Clients", - "position": 3, + "position": 5, "link": { "type": "generated-index", "description": "Language Model Clients in DSPy" diff --git a/docs/docs/deep-dive/retrieval_models_clients/_category_.json b/docs/docs/deep-dive/retrieval_models_clients/_category_.json index c2c3e449d..4422ec12e 100644 --- a/docs/docs/deep-dive/retrieval_models_clients/_category_.json +++ b/docs/docs/deep-dive/retrieval_models_clients/_category_.json @@ -1,6 +1,6 @@ { "label": "Retrieval Model Clients", - "position": 4, + "position": 6, "link": { "type": "generated-index", "description": "Retrieval Models in DSPy" diff --git a/docs/docs/deep-dive/teleprompter/_category_.json b/docs/docs/deep-dive/teleprompter/_category_.json index de6473d1e..c7be633ac 100644 --- a/docs/docs/deep-dive/teleprompter/_category_.json +++ b/docs/docs/deep-dive/teleprompter/_category_.json @@ -1,6 +1,6 @@ { "label": "Teleprompters", - "position": 5, + "position": 7, "link": { "type": "generated-index", "description": "Teleprompters are powerful optimizers (included in DSPy) that can learn to bootstrap and select effective prompts for the modules of any program. (The \"tele-\" in the name means \"at a distance\", i.e., automatic prompting at a distance.)" diff --git a/docs/docs/deep-dive/typed_predictors/_category_.json b/docs/docs/deep-dive/typed_predictors/_category_.json index e69de29bb..2b9a4e2f0 100644 --- a/docs/docs/deep-dive/typed_predictors/_category_.json +++ b/docs/docs/deep-dive/typed_predictors/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Typed Predictors", + "position": 4, + "link": { + "type": "generated-index", + "description": "Typed Predictors in DSPy" + } +} \ No newline at end of file From 2c9c67136627e613dab45e2c981a5d4772f8bbe3 Mon Sep 17 00:00:00 2001 From: arnavsinghvi11 <54859892+arnavsinghvi11@users.noreply.github.com> Date: Fri, 8 Mar 2024 11:03:03 -0800 Subject: [PATCH 53/79] Update 8-typed_predictors.md --- .../building-blocks/8-typed_predictors.md | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/docs/building-blocks/8-typed_predictors.md b/docs/docs/building-blocks/8-typed_predictors.md index 874fa29be..e8c7167c1 100644 --- a/docs/docs/building-blocks/8-typed_predictors.md +++ b/docs/docs/building-blocks/8-typed_predictors.md @@ -1,16 +1,16 @@ # Typed Predictors -In DSPy Signatures, we have `InputField` and `OutputField` that define the nature of inputs and outputs of the field. However the inputs and output to these fields is always string, you can seperately process these inputs and outputs in complicated scenarios but the inherent type is always `str`. +In DSPy Signatures, we have `InputField` and `OutputField` that define the nature of inputs and outputs of the field. However, the inputs and output to these fields are always `str`-typed, which requires input and output string processing. -Pydantic `BaseModel` is a great way to enforce type constraints on the fields, but it is not directly compatible with the `dspy.Signature`. This is where Typed Predictors come in. They are a way to enforce the type constraints on the inputs and outputs of the fields in a `dspy.Signature`. +Pydantic `BaseModel` is a great way to enforce type constraints on the fields, but it is not directly compatible with the `dspy.Signature`. Typed Predictors resolves this as a way to enforce the type constraints on the inputs and outputs of the fields in a `dspy.Signature`. ## Executing Typed Predictors -Using Typed Predictors is not too different than any other module, infact aside from adding type hints to signature attributes and using a special Predictor module instead of `dspy.Predict` there is nothing else to do. Let's take a look at a simple example to understand this. +Using Typed Predictors is not too different than any other module with the minor additions of type hints to signature attributes and using a special Predictor module instead of `dspy.Predict`. Let's take a look at a simple example to understand this. ### Defining Input and Output Models -Let's take an simple task as example i.e. given the `context` and `query` the LLM should give me an `answer` and `confidence_score`. The task could be modelled better but this is just for illustration purposes. Let's define our `Input` and `Output` models via pydantic. +Let's take a simple task as an example i.e. given the `context` and `query`, the LLM should return an `answer` and `confidence_score`. Let's define our `Input` and `Output` models via pydantic. ```python from pydantic import BaseModel, Field @@ -24,11 +24,11 @@ class Output(BaseModel): factual_: float = Field(..., description="The confidence score for the answer") ``` -As you can see this is where you can provide description to the attributes now. Now that we have the input and output models, let's define a simple Signature that takes in the input and returns the output. +As you can see, we can describe the attributes by defining a simple Signature that takes in the input and returns the output. ### Creating Typed Predictor -A Typed Predictor needs a Typed Signature which is not any different than a normal `dspy.Signature` everything is the same except here you provide type of each field as well. +A Typed Predictor needs a Typed Signature, which extends a `dspy.Signature` with the addition of specifying "field type". ```python class QASignature(dspy.Signature): @@ -38,17 +38,17 @@ class QASignature(dspy.Signature): output: Output = dspy.OutputField() ``` -Now that we have the `QASignature`, let's define a Typed Predictor that let's use execute this Signature while conforming to the type constraints. +Now that we have the `QASignature`, let's define a Typed Predictor that executes this Signature while conforming to the type constraints. ```python predictor = dspy.TypedPredictor(QASignature) ``` -Just how we pass the Signature to other modules we pass the `QASignature` to `dspy.TypedPredictor`, where typed constraints are inforced. +Similar to other modules, we pass the `QASignature` to `dspy.TypedPredictor` which enforces the typed constraints. ### I/O in Typed Predictors -Now that we have the Typed Predictor let's test it out by providing some sample input to the predictor and see the output and it's type. We can create a `Input` instance and pass it to the predictor to get a dictionary of the output. +Now let's test out the Typed Predictor by providing some sample input to the predictor and verifying the output type. We can create an `Input` instance and pass it to the predictor to get a dictionary of the output. ```python doc_query_pair = Input( @@ -59,7 +59,7 @@ doc_query_pair = Input( prediction = predictor(input=doc_query_pair) ``` -Now that we have the prediction, we can see the output and it's type. +Let's see the output and its type. ```python answer = prediction['answer'] @@ -72,7 +72,7 @@ print(f"Confidence Score: {confidence_score}, Confidence Score Type: {type(confi ## Typed Chain of Thoughts with `dspy.TypedChainOfThought` -If `TypedPredictor` is the typed counterpart of `dspy.Predict` then `TypedChainOfThought` is the typed counterpart of `dspy.ChainOfThought`. It adds a Chain of Thoughts `dspy.OutputField` to the `dspy.TypedPredictor` module by prepending it to the Signature. +Extending the analogous comparison of `TypedPredictor` to `dspy.Predict`, we create `TypedChainOfThought`, the typed counterpart of `dspy.ChainOfThought`: ```python cot_predictor = dspy.TypedChainOfThought(QASignature) @@ -87,7 +87,7 @@ prediction = cot_predictor(input=doc_query_pair) ## Typed Predictors as Decorators -While the `dspy.TypedPredictor` and `dspy.TypedChainOfThought` provide a convinient way to use typed predictors, you can also use their as decorators to enforce type constraints on the inputs and outputs of the function. Good thing is that you won't need to explicitly define a Signature class because it's created internally based on function arguments, outputs and docstring. +While the `dspy.TypedPredictor` and `dspy.TypedChainOfThought` provide a convenient way to use typed predictors, you can also use them as decorators to enforce type constraints on the inputs and outputs of the function. This relies on the internal definitions of the Signature class and its function arguments, outputs, and docstrings. ``` # Function name is output key @@ -105,7 +105,7 @@ def qa_function(doc_query_pair: Input) -> Output: ## Composing Functional Typed Predictors in `dspy.Module` -If you're creating DSPy pipelines via `dspy.Module` then you can simply use Functional Typed Predictors by creating these class methods and using them as decorators. Here is an example of using functional typed predictors to create a `SimplifiedBaleen` pipeline: +If you're creating DSPy pipelines via `dspy.Module`, then you can simply use Functional Typed Predictors by creating these class methods and using them as decorators. Here is an example of using functional typed predictors to create a `SimplifiedBaleen` pipeline: ```python class SimplifiedBaleen(FunctionalModule): @@ -138,7 +138,7 @@ class SimplifiedBaleen(FunctionalModule): ## Optimizing Typed Predictors -Typed predictors can be optimized using `optimize_signature` optimizer which optimizes the instructions of the Signature. Here is an example of using `optimize_signature` to optimize the `QASignature`: +Typed predictors can be optimized on the Signature instructions through the `optimize_signature` optimizer. Here is an example of this optimization on the `QASignature`: ```python import dspy @@ -161,4 +161,4 @@ result = optimize_signature( verbose=True, prompt_model=gpt4, ) -``` \ No newline at end of file +``` From e72ef1bc2e56058b348621602307dc3149d72424 Mon Sep 17 00:00:00 2001 From: dominik Date: Sat, 9 Mar 2024 13:15:37 +0100 Subject: [PATCH 54/79] =?UTF-8?q?=F0=9F=93=9D=20(ChromadbRM.md):=20Update?= =?UTF-8?q?=20the=20return=20type=20description=20in=20the=20documentation?= =?UTF-8?q?=20The=20return=20type=20description=20for=20the=20search=20fun?= =?UTF-8?q?ction=20in=20the=20ChromadbRM=20documentation=20was=20updated?= =?UTF-8?q?=20to=20provide=20more=20detailed=20information=20about=20the?= =?UTF-8?q?=20structure=20of=20the=20returned=20object.=20This=20change=20?= =?UTF-8?q?will=20help=20developers=20understand=20the=20structure=20of=20?= =?UTF-8?q?the=20returned=20object=20and=20how=20to=20use=20it=20in=20thei?= =?UTF-8?q?r=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api/retrieval_model_clients/ChromadbRM.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/retrieval_model_clients/ChromadbRM.md b/docs/api/retrieval_model_clients/ChromadbRM.md index 42f6f42e7..bbd1aaafd 100644 --- a/docs/api/retrieval_model_clients/ChromadbRM.md +++ b/docs/api/retrieval_model_clients/ChromadbRM.md @@ -34,7 +34,7 @@ Search the chromadb collection for the top `k` passages matching the given query - `k` (_Optional[int]_, _optional_): The number of results to retrieve. If not specified, defaults to the value set during initialization. **Returns:** -- `dspy.Prediction`: Contains the retrieved passages, each represented as a `dotdict` with a `long_text` attribute. +- `dspy.Prediction`: Contains the retrieved passages, each represented as a `dotdict` with schema `[{"id": str, "score": float, "long_text": str, "metadatas": dict }]` ### Quickstart with OpenAI Embeddings From 7b5e0d31f51d395f04bcae26d88934c413d761a4 Mon Sep 17 00:00:00 2001 From: Matthew Billman Date: Sat, 9 Mar 2024 11:53:18 -0500 Subject: [PATCH 55/79] hf models can use auth tokens now (#611) --- .pre-commit-config.yaml | 34 +- dsp/modules/hf.py | 76 ++- poetry.lock | 876 +++++++++++++++++++++++++++------ pyproject.toml | 5 +- tests/modules/test_hf_model.py | 31 ++ 5 files changed, 848 insertions(+), 174 deletions(-) create mode 100644 tests/modules/test_hf_model.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b78b22a8b..ff3243764 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,15 +5,15 @@ default_stages: [commit] default_install_hook_types: [pre-commit, commit-msg] repos: - - repo: https://github.com/astral-sh/ruff-pre-commit - # Ruff version. - rev: v0.1.11 - hooks: - # Run the linter. - - id: ruff - args: [--fix] - # Run the formatter. - - id: ruff-format + # - repo: https://github.com/astral-sh/ruff-pre-commit + # # Ruff version. + # rev: v0.1.11 + # hooks: + # # Run the linter. + # - id: ruff + # args: [--fix] + # # Run the formatter. + # - id: ruff-format - repo: https://github.com/timothycrosley/isort rev: 5.12.0 @@ -50,14 +50,14 @@ repos: args: - "--autofix" - "--indent=2" - - repo: local - hooks: - - id: validate-commit-msg - name: Commit Message is Valid - language: pygrep - entry: ^(break|build|ci|docs|feat|fix|perf|refactor|style|test|ops|hotfix|release|maint|init|enh|revert)\([\w,\.,\-,\(,\),\/]+\)(!?)(:)\s{1}([\w,\W,:]+) - stages: [commit-msg] - args: [--negate] + # - repo: local + # hooks: + # - id: validate-commit-msg + # name: Commit Message is Valid + # language: pygrep + # entry: ^(break|build|ci|docs|feat|fix|perf|refactor|style|test|ops|hotfix|release|maint|init|enh|revert)\([\w,\.,\-,\(,\),\/]+\)(!?)(:)\s{1}([\w,\W,:]+) + # stages: [commit-msg] + # args: [--negate] - repo: https://github.com/pre-commit/mirrors-prettier rev: v3.0.3 diff --git a/dsp/modules/hf.py b/dsp/modules/hf.py index aad0c0e36..7407b3f47 100644 --- a/dsp/modules/hf.py +++ b/dsp/modules/hf.py @@ -1,11 +1,13 @@ # from peft import PeftConfig, PeftModel # from transformers import AutoModelForSeq2SeqLM, AutoModelForCausalLM, AutoTokenizer, AutoConfig +import os from typing import Literal, Optional from dsp.modules.lm import LM # from dsp.modules.finetuning.finetune_hf import preprocess_prompt + def openai_to_hf(**kwargs): hf_kwargs = {} for k, v in kwargs.items(): @@ -26,8 +28,19 @@ def openai_to_hf(**kwargs): class HFModel(LM): - def __init__(self, model: str, checkpoint: Optional[str] = None, is_client: bool = False, - hf_device_map: Literal["auto", "balanced", "balanced_low_0", "sequential"] = "auto"): + def __init__( + self, + model: str, + checkpoint: Optional[str] = None, + is_client: bool = False, + hf_device_map: Literal[ + "auto", + "balanced", + "balanced_low_0", + "sequential", + ] = "auto", + token: Optional[str] = None, + ): """wrapper for Hugging Face models Args: @@ -42,6 +55,10 @@ def __init__(self, model: str, checkpoint: Optional[str] = None, is_client: bool self.provider = "hf" self.is_client = is_client self.device_map = hf_device_map + + hf_autoconfig_kwargs = dict(token=token or os.environ.get("HF_TOKEN")) + hf_autotokenizer_kwargs = hf_autoconfig_kwargs.copy() + hf_automodel_kwargs = hf_autoconfig_kwargs.copy() if not self.is_client: try: import torch @@ -52,40 +69,68 @@ def __init__(self, model: str, checkpoint: Optional[str] = None, is_client: bool ) from exc self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") try: - architecture = AutoConfig.from_pretrained(model).__dict__["architectures"][0] - self.encoder_decoder_model = ("ConditionalGeneration" in architecture) or ("T5WithLMHeadModel" in architecture) + architecture = AutoConfig.from_pretrained( + model, + **hf_autoconfig_kwargs, + ).__dict__["architectures"][0] + self.encoder_decoder_model = ("ConditionalGeneration" in architecture) or ( + "T5WithLMHeadModel" in architecture + ) self.decoder_only_model = ("CausalLM" in architecture) or ("GPT2LMHeadModel" in architecture) - assert self.encoder_decoder_model or self.decoder_only_model, f"Unknown HuggingFace model class: {model}" - self.tokenizer = AutoTokenizer.from_pretrained(model if checkpoint is None else checkpoint) + assert ( + self.encoder_decoder_model or self.decoder_only_model + ), f"Unknown HuggingFace model class: {model}" + self.tokenizer = AutoTokenizer.from_pretrained( + model if checkpoint is None else checkpoint, + **hf_autotokenizer_kwargs, + ) self.rationale = True AutoModelClass = AutoModelForSeq2SeqLM if self.encoder_decoder_model else AutoModelForCausalLM if checkpoint: # with open(os.path.join(checkpoint, '..', 'compiler_config.json'), 'r') as f: # config = json.load(f) - self.rationale = False #config['rationale'] + self.rationale = False # config['rationale'] # if config['peft']: # peft_config = PeftConfig.from_pretrained(checkpoint) # self.model = AutoModelClass.from_pretrained(peft_config.base_model_name_or_path, return_dict=True, load_in_8bit=True, device_map=hf_device_map) # self.model = PeftModel.from_pretrained(self.model, checkpoint) # else: if self.device_map: - self.model = AutoModelClass.from_pretrained(checkpoint, device_map=self.device_map) + self.model = AutoModelClass.from_pretrained( + checkpoint, + device_map=self.device_map, + **hf_automodel_kwargs, + ) else: - self.model = AutoModelClass.from_pretrained(checkpoint).to(self.device) + self.model = AutoModelClass.from_pretrained( + checkpoint, + **hf_automodel_kwargs, + ).to(self.device) else: if self.device_map: - self.model = AutoModelClass.from_pretrained(model, device_map=self.device_map) + self.model = AutoModelClass.from_pretrained( + model, + device_map=self.device_map, + **hf_automodel_kwargs, + ) else: - self.model = AutoModelClass.from_pretrained(model).to(self.device) + self.model = AutoModelClass.from_pretrained( + model, + **hf_automodel_kwargs, + ).to(self.device) self.drop_prompt_from_output = False except ValueError: self.model = AutoModelForCausalLM.from_pretrained( model if checkpoint is None else checkpoint, device_map=self.device_map, + **hf_automodel_kwargs, ) self.drop_prompt_from_output = True - self.tokenizer = AutoTokenizer.from_pretrained(model) + self.tokenizer = AutoTokenizer.from_pretrained( + model, + **hf_autotokenizer_kwargs, + ) self.drop_prompt_from_output = True self.history = [] @@ -111,7 +156,7 @@ def _generate(self, prompt, **kwargs): # print(prompt) if isinstance(prompt, dict): try: - prompt = prompt['messages'][0]['content'] + prompt = prompt["messages"][0]["content"] except (KeyError, IndexError, TypeError): print("Failed to extract 'content' from the prompt.") inputs = self.tokenizer(prompt, return_tensors="pt").to(self.device) @@ -121,10 +166,7 @@ def _generate(self, prompt, **kwargs): if self.drop_prompt_from_output: input_length = inputs.input_ids.shape[1] outputs = outputs[:, input_length:] - completions = [ - {"text": c} - for c in self.tokenizer.batch_decode(outputs, skip_special_tokens=True) - ] + completions = [{"text": c} for c in self.tokenizer.batch_decode(outputs, skip_special_tokens=True)] response = { "prompt": prompt, "choices": completions, diff --git a/poetry.lock b/poetry.lock index 136e7473b..236ee5829 100644 --- a/poetry.lock +++ b/poetry.lock @@ -364,6 +364,52 @@ charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] +[[package]] +name = "black" +version = "24.2.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"}, + {file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"}, + {file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"}, + {file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"}, + {file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"}, + {file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"}, + {file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"}, + {file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"}, + {file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"}, + {file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"}, + {file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"}, + {file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"}, + {file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"}, + {file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"}, + {file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"}, + {file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"}, + {file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"}, + {file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"}, + {file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"}, + {file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"}, + {file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"}, + {file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "cachetools" version = "5.3.3" @@ -951,20 +997,21 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "fastembed" -version = "0.1.1" +version = "0.1.3" description = "Fast, light, accurate library built for retrieval embedding generation" optional = true python-versions = ">=3.8.0,<3.12" files = [ - {file = "fastembed-0.1.1-py3-none-any.whl", hash = "sha256:131413ae52cd72f4c8cced7a675f8269dbfd1a852abade3c815e265114bcc05a"}, - {file = "fastembed-0.1.1.tar.gz", hash = "sha256:f7e524ee4f74bb8aad16be5b687d1f77f608d40e96e292c87881dc36baf8f4c7"}, + {file = "fastembed-0.1.3-py3-none-any.whl", hash = "sha256:98b6c6d9effec8c96d97048e59cdd53627b16a70fcdbfa7c663772de66e11b3a"}, + {file = "fastembed-0.1.3.tar.gz", hash = "sha256:c17dc83a02938f8baae6717f18d24ed0ff0c5397b5329cbb5c7264239411346f"}, ] [package.dependencies] +huggingface-hub = "0.19.4" onnx = ">=1.11,<2.0" onnxruntime = ">=1.15,<2.0" requests = ">=2.31,<3.0" -tokenizers = ">=0.13,<0.14" +tokenizers = ">=0.15.0,<0.16.0" tqdm = ">=4.65,<5.0" [[package]] @@ -999,13 +1046,13 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "flatbuffers" -version = "23.5.26" +version = "24.3.7" description = "The FlatBuffers serialization format for Python" optional = true 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"}, + {file = "flatbuffers-24.3.7-py2.py3-none-any.whl", hash = "sha256:80c4f5dcad0ee76b7e349671a0d657f2fbba927a0244f88dd3f5ed6a3694e1fc"}, + {file = "flatbuffers-24.3.7.tar.gz", hash = "sha256:0895c22b9a6019ff2f4de2e5e2f7cd15914043e6e7033a94c0c6369422690f22"}, ] [[package]] @@ -1558,13 +1605,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" -version = "0.21.3" +version = "0.19.4" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.21.3-py3-none-any.whl", hash = "sha256:b183144336fdf2810a8c109822e0bb6ef1fd61c65da6fb60e8c3f658b7144016"}, - {file = "huggingface_hub-0.21.3.tar.gz", hash = "sha256:26a15b604e4fc7bad37c467b76456543ec849386cbca9cd7e1e135f53e500423"}, + {file = "huggingface_hub-0.19.4-py3-none-any.whl", hash = "sha256:dba013f779da16f14b606492828f3760600a1e1801432d09fe1c33e50b825bb5"}, + {file = "huggingface_hub-0.19.4.tar.gz", hash = "sha256:176a4fc355a851c17550e7619488f383189727eab209534d7cef2114dae77b22"}, ] [package.dependencies] @@ -1577,16 +1624,16 @@ tqdm = ">=4.42.1" typing-extensions = ">=3.7.4.3" [package.extras] -all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] cli = ["InquirerPy (==0.3.4)"] -dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +docs = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "hf-doc-builder", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)", "watchdog"] fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] -hf-transfer = ["hf-transfer (>=0.1.4)"] inference = ["aiohttp", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)"] quality = ["mypy (==1.5.1)", "ruff (>=0.1.3)"] tensorflow = ["graphviz", "pydot", "tensorflow"] -testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] -torch = ["safetensors", "torch"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +torch = ["torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] [[package]] @@ -1638,32 +1685,32 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "7.0.2" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, - {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, + {file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"}, + {file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "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"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.1.2" +version = "6.1.3" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.2-py3-none-any.whl", hash = "sha256:9a0a862501dc38b68adebc82970140c9e4209fc99601782925178f8386339938"}, - {file = "importlib_resources-6.1.2.tar.gz", hash = "sha256:308abf8474e2dba5f867d279237cd4076482c3de7104a40b41426370e891549b"}, + {file = "importlib_resources-6.1.3-py3-none-any.whl", hash = "sha256:4c0269e3580fe2634d364b39b38b961540a7738c02cb984e98add8b4221d793d"}, + {file = "importlib_resources-6.1.3.tar.gz", hash = "sha256:56fb4525197b78544a3354ea27793952ab93f935bb4bf746b846bb1015020f2b"}, ] [package.dependencies] @@ -1671,7 +1718,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +testing = ["jaraco.collections", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -2279,13 +2326,13 @@ mkdocs = ">=1.0.3" [[package]] name = "mkdocs-material" -version = "9.5.12" +version = "9.5.13" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.12-py3-none-any.whl", hash = "sha256:d6f0c269f015e48c76291cdc79efb70f7b33bbbf42d649cfe475522ebee61b1f"}, - {file = "mkdocs_material-9.5.12.tar.gz", hash = "sha256:5f69cef6a8aaa4050b812f72b1094fda3d079b9a51cf27a247244c03ec455e97"}, + {file = "mkdocs_material-9.5.13-py3-none-any.whl", hash = "sha256:5cbe17fee4e3b4980c8420a04cc762d8dc052ef1e10532abd4fce88e5ea9ce6a"}, + {file = "mkdocs_material-9.5.13.tar.gz", hash = "sha256:d8e4caae576312a88fd2609b81cf43d233cdbe36860d67a68702b018b425bd87"}, ] [package.dependencies] @@ -2376,7 +2423,7 @@ files = [ name = "mpmath" version = "1.3.0" description = "Python library for arbitrary-precision floating-point arithmetic" -optional = true +optional = false python-versions = "*" files = [ {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, @@ -2512,6 +2559,17 @@ files = [ [package.dependencies] dill = ">=0.3.8" +[[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 = "myst-nb" version = "1.0.0" @@ -2620,6 +2678,24 @@ files = [ {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, ] +[[package]] +name = "networkx" +version = "3.2.1" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.9" +files = [ + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, +] + +[package.extras] +default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "numpy" version = "1.26.4" @@ -2665,6 +2741,147 @@ files = [ {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] +[[package]] +name = "nvidia-cublas-cu12" +version = "12.1.3.1" +description = "CUBLAS native runtime libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"}, + {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"}, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.1.105" +description = "CUDA profiling tools runtime libs." +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"}, + {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"}, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.1.105" +description = "NVRTC native runtime libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"}, + {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"}, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.1.105" +description = "CUDA Runtime native Libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"}, + {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"}, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "8.9.2.26" +description = "cuDNN runtime libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.0.2.54" +description = "CUFFT native runtime libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"}, + {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"}, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.2.106" +description = "CURAND native runtime libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"}, + {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"}, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.4.5.107" +description = "CUDA solver native runtime libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"}, + {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.1.0.106" +description = "CUSPARSE native runtime libraries" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"}, + {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.19.3" +description = "NVIDIA Collective Communication Library (NCCL) Runtime" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl", hash = "sha256:a9734707a2c96443331c1e48c717024aa6678a0e2a4cb66b2c364d18cee6b48d"}, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.4.99" +description = "Nvidia JIT LTO Library" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_nvjitlink_cu12-12.4.99-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c6428836d20fe7e327191c175791d38570e10762edc588fb46749217cd444c74"}, + {file = "nvidia_nvjitlink_cu12-12.4.99-py3-none-win_amd64.whl", hash = "sha256:991905ffa2144cb603d8ca7962d75c35334ae82bf92820b6ba78157277da1ad2"}, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.1.105" +description = "NVIDIA Tools Extension" +optional = false +python-versions = ">=3" +files = [ + {file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"}, + {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"}, +] + [[package]] name = "oauthlib" version = "3.2.2" @@ -3281,47 +3498,47 @@ files = [ [[package]] name = "pyarrow" -version = "15.0.0" +version = "15.0.1" description = "Python library for Apache Arrow" optional = false python-versions = ">=3.8" files = [ - {file = "pyarrow-15.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0a524532fd6dd482edaa563b686d754c70417c2f72742a8c990b322d4c03a15d"}, - {file = "pyarrow-15.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:60a6bdb314affa9c2e0d5dddf3d9cbb9ef4a8dddaa68669975287d47ece67642"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66958fd1771a4d4b754cd385835e66a3ef6b12611e001d4e5edfcef5f30391e2"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f500956a49aadd907eaa21d4fff75f73954605eaa41f61cb94fb008cf2e00c6"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6f87d9c4f09e049c2cade559643424da84c43a35068f2a1c4653dc5b1408a929"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85239b9f93278e130d86c0e6bb455dcb66fc3fd891398b9d45ace8799a871a1e"}, - {file = "pyarrow-15.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b8d43e31ca16aa6e12402fcb1e14352d0d809de70edd185c7650fe80e0769e3"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:fa7cd198280dbd0c988df525e50e35b5d16873e2cdae2aaaa6363cdb64e3eec5"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8780b1a29d3c8b21ba6b191305a2a607de2e30dab399776ff0aa09131e266340"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0ec198ccc680f6c92723fadcb97b74f07c45ff3fdec9dd765deb04955ccf19"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036a7209c235588c2f07477fe75c07e6caced9b7b61bb897c8d4e52c4b5f9555"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bd8a0e5296797faf9a3294e9fa2dc67aa7f10ae2207920dbebb785c77e9dbe5"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e8ebed6053dbe76883a822d4e8da36860f479d55a762bd9e70d8494aed87113e"}, - {file = "pyarrow-15.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d53a9d1b2b5bd7d5e4cd84d018e2a45bc9baaa68f7e6e3ebed45649900ba99"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9950a9c9df24090d3d558b43b97753b8f5867fb8e521f29876aa021c52fda351"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:003d680b5e422d0204e7287bb3fa775b332b3fce2996aa69e9adea23f5c8f970"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f75fce89dad10c95f4bf590b765e3ae98bcc5ba9f6ce75adb828a334e26a3d40"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca9cb0039923bec49b4fe23803807e4ef39576a2bec59c32b11296464623dc2"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ed5a78ed29d171d0acc26a305a4b7f83c122d54ff5270810ac23c75813585e4"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6eda9e117f0402dfcd3cd6ec9bfee89ac5071c48fc83a84f3075b60efa96747f"}, - {file = "pyarrow-15.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a3a6180c0e8f2727e6f1b1c87c72d3254cac909e609f35f22532e4115461177"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:19a8918045993349b207de72d4576af0191beef03ea655d8bdb13762f0cd6eac"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0ec076b32bacb6666e8813a22e6e5a7ef1314c8069d4ff345efa6246bc38593"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5db1769e5d0a77eb92344c7382d6543bea1164cca3704f84aa44e26c67e320fb"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2617e3bf9df2a00020dd1c1c6dce5cc343d979efe10bc401c0632b0eef6ef5b"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:d31c1d45060180131caf10f0f698e3a782db333a422038bf7fe01dace18b3a31"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:c8c287d1d479de8269398b34282e206844abb3208224dbdd7166d580804674b7"}, - {file = "pyarrow-15.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:07eb7f07dc9ecbb8dace0f58f009d3a29ee58682fcdc91337dfeb51ea618a75b"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:47af7036f64fce990bb8a5948c04722e4e3ea3e13b1007ef52dfe0aa8f23cf7f"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93768ccfff85cf044c418bfeeafce9a8bb0cee091bd8fd19011aff91e58de540"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ee87fd6892700960d90abb7b17a72a5abb3b64ee0fe8db6c782bcc2d0dc0b4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:001fca027738c5f6be0b7a3159cc7ba16a5c52486db18160909a0831b063c4e4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:d1c48648f64aec09accf44140dccb92f4f94394b8d79976c426a5b79b11d4fa7"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:972a0141be402bb18e3201448c8ae62958c9c7923dfaa3b3d4530c835ac81aed"}, - {file = "pyarrow-15.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:f01fc5cf49081426429127aa2d427d9d98e1cb94a32cb961d583a70b7c4504e6"}, - {file = "pyarrow-15.0.0.tar.gz", hash = "sha256:876858f549d540898f927eba4ef77cd549ad8d24baa3207cf1b72e5788b50e83"}, + {file = "pyarrow-15.0.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:c2ddb3be5ea938c329a84171694fc230b241ce1b6b0ff1a0280509af51c375fa"}, + {file = "pyarrow-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7543ea88a0ff72f8e6baaf9bfdbec2c62aeabdbede9e4a571c71cc3bc43b6302"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1519e218a6941fc074e4501088d891afcb2adf77c236e03c34babcf3d6a0d1c7"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28cafa86e1944761970d3b3fc0411b14ff9b5c2b73cd22aaf470d7a3976335f5"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:be5c3d463e33d03eab496e1af7916b1d44001c08f0f458ad27dc16093a020638"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:47b1eda15d3aa3f49a07b1808648e1397e5dc6a80a30bf87faa8e2d02dad7ac3"}, + {file = "pyarrow-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e524a31be7db22deebbbcf242b189063ab9a7652c62471d296b31bc6e3cae77b"}, + {file = "pyarrow-15.0.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:a476fefe8bdd56122fb0d4881b785413e025858803cc1302d0d788d3522b374d"}, + {file = "pyarrow-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:309e6191be385f2e220586bfdb643f9bb21d7e1bc6dd0a6963dc538e347b2431"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83bc586903dbeb4365cbc72b602f99f70b96c5882e5dfac5278813c7d624ca3c"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e652daac6d8b05280cd2af31c0fb61a4490ec6a53dc01588014d9fa3fdbee9"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:abad2e08652df153a72177ce20c897d083b0c4ebeec051239e2654ddf4d3c996"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cde663352bc83ad75ba7b3206e049ca1a69809223942362a8649e37bd22f9e3b"}, + {file = "pyarrow-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1b6e237dd7a08482a8b8f3f6512d258d2460f182931832a8c6ef3953203d31e1"}, + {file = "pyarrow-15.0.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:7bd167536ee23192760b8c731d39b7cfd37914c27fd4582335ffd08450ff799d"}, + {file = "pyarrow-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7c08bb31eb2984ba5c3747d375bb522e7e536b8b25b149c9cb5e1c49b0ccb736"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0f9c1d630ed2524bd1ddf28ec92780a7b599fd54704cd653519f7ff5aec177a"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5186048493395220550bca7b524420471aac2d77af831f584ce132680f55c3df"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:31dc30c7ec8958da3a3d9f31d6c3630429b2091ede0ecd0d989fd6bec129f0e4"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3f111a014fb8ac2297b43a74bf4495cc479a332908f7ee49cb7cbd50714cb0c1"}, + {file = "pyarrow-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a6d1f7c15d7f68f08490d0cb34611497c74285b8a6bbeab4ef3fc20117310983"}, + {file = "pyarrow-15.0.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:9ad931b996f51c2f978ed517b55cb3c6078272fb4ec579e3da5a8c14873b698d"}, + {file = "pyarrow-15.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:738f6b53ab1c2f66b2bde8a1d77e186aeaab702d849e0dfa1158c9e2c030add3"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c1c3fc16bc74e33bf8f1e5a212938ed8d88e902f372c4dac6b5bad328567d2f"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1fa92512128f6c1b8dde0468c1454dd70f3bff623970e370d52efd4d24fd0be"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:b4157f307c202cbbdac147d9b07447a281fa8e63494f7fc85081da351ec6ace9"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:b75e7da26f383787f80ad76143b44844ffa28648fcc7099a83df1538c078d2f2"}, + {file = "pyarrow-15.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:3a99eac76ae14096c209850935057b9e8ce97a78397c5cde8724674774f34e5d"}, + {file = "pyarrow-15.0.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:dd532d3177e031e9b2d2df19fd003d0cc0520d1747659fcabbd4d9bb87de508c"}, + {file = "pyarrow-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ce8c89848fd37e5313fc2ce601483038ee5566db96ba0808d5883b2e2e55dc53"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:862eac5e5f3b6477f7a92b2f27e560e1f4e5e9edfca9ea9da8a7478bb4abd5ce"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f0ea3a29cd5cb99bf14c1c4533eceaa00ea8fb580950fb5a89a5c771a994a4e"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:bb902f780cfd624b2e8fd8501fadab17618fdb548532620ef3d91312aaf0888a"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:4f87757f02735a6bb4ad2e1b98279ac45d53b748d5baf52401516413007c6999"}, + {file = "pyarrow-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:efd3816c7fbfcbd406ac0f69873cebb052effd7cdc153ae5836d1b00845845d7"}, + {file = "pyarrow-15.0.1.tar.gz", hash = "sha256:21d812548d39d490e0c6928a7c663f37b96bf764034123d4b4ab4530ecc757a9"}, ] [package.dependencies] @@ -3560,13 +3777,13 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pyparsing" -version = "3.1.1" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -3617,6 +3834,23 @@ toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "pytest-mock" +version = "3.12.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, + {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -3704,7 +3938,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3860,13 +4093,13 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "qdrant-client" -version = "1.7.3" +version = "1.8.0" description = "Client library for the Qdrant vector search engine" optional = true python-versions = ">=3.8" files = [ - {file = "qdrant_client-1.7.3-py3-none-any.whl", hash = "sha256:b062420ba55eb847652c7d2a26404fb1986bea13aa785763024013f96a7a915c"}, - {file = "qdrant_client-1.7.3.tar.gz", hash = "sha256:7b809be892cdc5137ae80ea3335da40c06499ad0b0072b5abc6bad79da1d29fc"}, + {file = "qdrant_client-1.8.0-py3-none-any.whl", hash = "sha256:fa28d3eb64c0c57ec029c7c85c71f6c72c197f92502022655741f3632c518e29"}, + {file = "qdrant_client-1.8.0.tar.gz", hash = "sha256:2a1a3f2cbacc7adba85644cf6cfdee20401cf25764b32da479c81fb63e178d15"}, ] [package.dependencies] @@ -3879,7 +4112,7 @@ pydantic = ">=1.10.8" urllib3 = ">=1.26.14,<3" [package.extras] -fastembed = ["fastembed (==0.1.1)"] +fastembed = ["fastembed (==0.2.2)"] [[package]] name = "referencing" @@ -4161,30 +4394,162 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.3.0" +version = "0.3.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.3.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7deb528029bacf845bdbb3dbb2927d8ef9b4356a5e731b10eef171e3f0a85944"}, - {file = "ruff-0.3.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e1e0d4381ca88fb2b73ea0766008e703f33f460295de658f5467f6f229658c19"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f7dbba46e2827dfcb0f0cc55fba8e96ba7c8700e0a866eb8cef7d1d66c25dcb"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23dbb808e2f1d68eeadd5f655485e235c102ac6f12ad31505804edced2a5ae77"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ef655c51f41d5fa879f98e40c90072b567c666a7114fa2d9fe004dffba00932"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d0d3d7ef3d4f06433d592e5f7d813314a34601e6c5be8481cccb7fa760aa243e"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b08b356d06a792e49a12074b62222f9d4ea2a11dca9da9f68163b28c71bf1dd4"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9343690f95710f8cf251bee1013bf43030072b9f8d012fbed6ad702ef70d360a"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1f3ed501a42f60f4dedb7805fa8d4534e78b4e196f536bac926f805f0743d49"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:cc30a9053ff2f1ffb505a585797c23434d5f6c838bacfe206c0e6cf38c921a1e"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5da894a29ec018a8293d3d17c797e73b374773943e8369cfc50495573d396933"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:755c22536d7f1889be25f2baf6fedd019d0c51d079e8417d4441159f3bcd30c2"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd73fe7f4c28d317855da6a7bc4aa29a1500320818dd8f27df95f70a01b8171f"}, - {file = "ruff-0.3.0-py3-none-win32.whl", hash = "sha256:19eacceb4c9406f6c41af806418a26fdb23120dfe53583df76d1401c92b7c14b"}, - {file = "ruff-0.3.0-py3-none-win_amd64.whl", hash = "sha256:128265876c1d703e5f5e5a4543bd8be47c73a9ba223fd3989d4aa87dd06f312f"}, - {file = "ruff-0.3.0-py3-none-win_arm64.whl", hash = "sha256:e3a4a6d46aef0a84b74fcd201a4401ea9a6cd85614f6a9435f2d33dd8cefbf83"}, - {file = "ruff-0.3.0.tar.gz", hash = "sha256:0886184ba2618d815067cf43e005388967b67ab9c80df52b32ec1152ab49f53a"}, + {file = "ruff-0.3.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6b82e3937d0d76554cd5796bc3342a7d40de44494d29ff490022d7a52c501744"}, + {file = "ruff-0.3.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ae7954c8f692b70e6a206087ae3988acc9295d84c550f8d90b66c62424c16771"}, + {file = "ruff-0.3.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b730f56ccf91225da0f06cfe421e83b8cc27b2a79393db9c3df02ed7e2bbc01"}, + {file = "ruff-0.3.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c78bfa85637668f47bd82aa2ae17de2b34221ac23fea30926f6409f9e37fc927"}, + {file = "ruff-0.3.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6abaad602d6e6daaec444cbf4d9364df0a783e49604c21499f75bb92237d4af"}, + {file = "ruff-0.3.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5f0c21b6914c3c9a25a59497cbb1e5b6c2d8d9beecc9b8e03ee986e24eee072e"}, + {file = "ruff-0.3.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:434c3fc72e6311c85cd143c4c448b0e60e025a9ac1781e63ba222579a8c29200"}, + {file = "ruff-0.3.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78a7025e6312cbba496341da5062e7cdd47d95f45c1b903e635cdeb1ba5ec2b9"}, + {file = "ruff-0.3.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52b02bb46f1a79b0c1fa93f6495bc7e77e4ef76e6c28995b4974a20ed09c0833"}, + {file = "ruff-0.3.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11b5699c42f7d0b771c633d620f2cb22e727fb226273aba775a91784a9ed856c"}, + {file = "ruff-0.3.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:54e5dca3e411772b51194b3102b5f23b36961e8ede463776b289b78180df71a0"}, + {file = "ruff-0.3.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:951efb610c5844e668bbec4f71cf704f8645cf3106e13f283413969527ebfded"}, + {file = "ruff-0.3.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:09c7333b25e983aabcf6e38445252cff0b4745420fc3bda45b8fce791cc7e9ce"}, + {file = "ruff-0.3.1-py3-none-win32.whl", hash = "sha256:d937f9b99ebf346e0606c3faf43c1e297a62ad221d87ef682b5bdebe199e01f6"}, + {file = "ruff-0.3.1-py3-none-win_amd64.whl", hash = "sha256:c0318a512edc9f4e010bbaab588b5294e78c5cdc9b02c3d8ab2d77c7ae1903e3"}, + {file = "ruff-0.3.1-py3-none-win_arm64.whl", hash = "sha256:d3b60e44240f7e903e6dbae3139a65032ea4c6f2ad99b6265534ff1b83c20afa"}, + {file = "ruff-0.3.1.tar.gz", hash = "sha256:d30db97141fc2134299e6e983a6727922c9e03c031ae4883a6d69461de722ae7"}, +] + +[[package]] +name = "safetensors" +version = "0.4.2" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "safetensors-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:69d8bb8384dc2cb5b72c36c4d6980771b293d1a1377b378763f5e37b6bb8d133"}, + {file = "safetensors-0.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3d420e19fcef96d0067f4de4699682b4bbd85fc8fea0bd45fcd961fdf3e8c82c"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ca54742122fa3c4821754adb67318e1cd25c3a22bbf0c5520d5176e77a099ac"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b47aa643afdfd66cf7ce4c184092ae734e15d10aba2c2948f24270211801c3c"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d88a16bbc330f27e7f2d4caaf6fb061ad0b8a756ecc4033260b0378e128ce8a2"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9223b8ac21085db614a510eb3445e7083cae915a9202357555fa939695d4f57"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6cb86133dc8930a7ab5e7438545a7f205f7a1cdd5aaf108c1d0da6bdcfbc2b"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8a628e0ae2bbc334b62952c384aa5f41621d01850f8d67b04a96b9c39dd7326"}, + {file = "safetensors-0.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:88d6beb7f811a081e0e5f1d9669fdac816c45340c04b1eaf7ebfda0ce93ea403"}, + {file = "safetensors-0.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b57fc5b1b54cb12d8690a58a4cf4b7144730d4bde9d98aa0e1dab6295a1cd579"}, + {file = "safetensors-0.4.2-cp310-none-win32.whl", hash = "sha256:9d87a1c98803c16cf113b9ba03f07b2dce5e8eabfd1811a7f7323fcaa2a1bf47"}, + {file = "safetensors-0.4.2-cp310-none-win_amd64.whl", hash = "sha256:18930ec1d1ecb526d3d9835abc2489b8f1530877518f0c541e77ef0b7abcbd99"}, + {file = "safetensors-0.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c5dd2ed788730ed56b415d1a11c62026b8cc8c573f55a2092afb3ab383e94fff"}, + {file = "safetensors-0.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc41791b33efb9c83a59b731619f3d15f543dfe71f3a793cb8fbf9bd5d0d5d71"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c888bf71d5ca12a720f1ed87d407c4918afa022fb247a6546d8fac15b1f112b"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e6b2feb4b47226a16a792e6fac3f49442714884a3d4c1008569d5068a3941be9"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f41cc0ee4b838ae8f4d8364a1b162067693d11a3893f0863be8c228d40e4d0ee"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:51b7228e46c0a483c40ba4b9470dea00fb1ff8685026bb4766799000f6328ac2"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02697f8f2be8ca3c37a4958702dbdb1864447ef765e18b5328a1617022dcf164"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:27fd8f65cf7c80e4280cae1ee6bcd85c483882f6580821abe71ee1a0d3dcfca7"}, + {file = "safetensors-0.4.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c487b5f113b0924c9534a07dc034830fb4ef05ce9bb6d78cfe016a7dedfe281f"}, + {file = "safetensors-0.4.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:da7f6483f3fe67ff39b3a55552552c67930ea10a36e9f2539d36fc205273d767"}, + {file = "safetensors-0.4.2-cp311-none-win32.whl", hash = "sha256:52a7012f6cb9cb4a132760b6308daede18a9f5f8952ce08adc7c67a7d865c2d8"}, + {file = "safetensors-0.4.2-cp311-none-win_amd64.whl", hash = "sha256:4d1361a097ac430b310ce9eed8ed4746edee33ddafdfbb965debc8966fc34dc2"}, + {file = "safetensors-0.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:77af8aa0edcc2863760fd6febbfdb82e88fd75d0e60c1ce4ba57208ba5e4a89b"}, + {file = "safetensors-0.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846666c1c5a8c8888d2dfda8d3921cb9cb8e2c5f78365be756c11021e75a0a2a"}, + {file = "safetensors-0.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f4bfc7ea19b446bfad41510d4b4c76101698c00caaa8a332c8edd8090a412ef"}, + {file = "safetensors-0.4.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:233436fd30f27ffeb3c3780d0b84f496518868445c7a8db003639a649cc98453"}, + {file = "safetensors-0.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a09237a795d11cd11f9dae505d170a29b5616151db1e10c14f892b11caadc7d"}, + {file = "safetensors-0.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de01c9a3a3b7b69627d624ff69d9f11d28ce9908eea2fb6245adafa4b1d43df6"}, + {file = "safetensors-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1f25c5069ee42a5bcffdc66c300a407941edd73f3239e9fdefd26216407391"}, + {file = "safetensors-0.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7a73b3649456d09ca8506140d44484b63154a7378434cc1e8719f8056550b224"}, + {file = "safetensors-0.4.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e1625a8d07d046e968bd5c4961810aba1225984e4fb9243626f9d04a06ed3fee"}, + {file = "safetensors-0.4.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f74c86b25615cb24ad4cff765a2eefc09d71bf0fed97588cf585aad9c38fbb4"}, + {file = "safetensors-0.4.2-cp312-none-win32.whl", hash = "sha256:8523b9c5777d771bcde5c2389c03f1cdf7ebe8797432a1bd5e345efe25c55987"}, + {file = "safetensors-0.4.2-cp312-none-win_amd64.whl", hash = "sha256:dcff0243e1737a21f83d664c63fed89d1f532c23fc6830d0427279fabd789ccb"}, + {file = "safetensors-0.4.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:96ad3d7d472612e26cbe413922b4fb13933310f0511d346ea5cc9a1e856e52eb"}, + {file = "safetensors-0.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:88250922401b5ae4e37de929178caf46be47ed16c817b2237b81679bec07c120"}, + {file = "safetensors-0.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d40443554142fc0ab30652d5cc8554c4b7a613513bde00373e18afd5de8cbe4b"}, + {file = "safetensors-0.4.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:27f53f70106224d32d874aacecbeb4a6e4c5b16a1d2006d0e876d97229086d71"}, + {file = "safetensors-0.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cc068afe23734dfb26ce19db0a7877499ddf73b1d55ceb762417e8da4a1b05fb"}, + {file = "safetensors-0.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9be1918eb8d43a11a6f8806759fccfa0eeb0542b12924caba66af8a7800ad01a"}, + {file = "safetensors-0.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41911087d20a7bbd78cb4ad4f98aab0c431533107584df6635d8b54b99945573"}, + {file = "safetensors-0.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50771c662aab909f31e94d048e76861fd027d66076ea773eef2e66c717766e24"}, + {file = "safetensors-0.4.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13f2e57be007b7ea9329133d2399e6bdfcf1910f655440a4da17df3a45afcd30"}, + {file = "safetensors-0.4.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c772147e6395bc829842e0a98e1b30c67fe25d816299c28196488511d5a5e951"}, + {file = "safetensors-0.4.2-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:36239a0060b537a3e8c473df78cffee14c3ec4f51d5f1a853af99371a2fb2a35"}, + {file = "safetensors-0.4.2-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:d0cbb7664fad2c307f95195f951b7059e95dc23e0e1822e5978c8b500098543c"}, + {file = "safetensors-0.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b3e55adb6bd9dc1c2a341e72f48f075953fa35d173dd8e29a95b3b02d0d1462"}, + {file = "safetensors-0.4.2-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42f743b3cca863fba53ca57a193f510e5ec359b97f38c282437716b6768e4a25"}, + {file = "safetensors-0.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04e6af4a6dbeb06c4e6e7d46cf9c716cbc4cc5ef62584fd8a7c0fe558562df45"}, + {file = "safetensors-0.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a492ba21b5c8f14ee5ec9b20f42ba969e53ca1f909a4d04aad736b66a341dcc2"}, + {file = "safetensors-0.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b25b8233a1a85dc67e39838951cfb01595d792f3b7b644add63edb652992e030"}, + {file = "safetensors-0.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd27e063fbdafe776f7b1714da59110e88f270e86db00788a8fd65f4eacfeba7"}, + {file = "safetensors-0.4.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1b6fa399f251bbeb52029bf5a0ac2878d7705dd3612a2f8895b48e9c11f0367d"}, + {file = "safetensors-0.4.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de642d46b459e4afd5c2020b26c0d6d869a171ea00411897d5776c127cac74f0"}, + {file = "safetensors-0.4.2-cp37-none-win32.whl", hash = "sha256:77b72d17754c93bb68f3598182f14d78776e0b9b31682ca5bb2c7c5bd9a75267"}, + {file = "safetensors-0.4.2-cp37-none-win_amd64.whl", hash = "sha256:d36ee3244d461cd655aeef493792c3bccf4875282f8407fd9af99e9a41cf2530"}, + {file = "safetensors-0.4.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:16b6b3884f7876c6b3b23a742428223a7170a5a9dac819d8c12a1569422c4b5a"}, + {file = "safetensors-0.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ee25d311493fbbe0be9d395faee46e9d79e8948f461e388ff39e59875ed9a350"}, + {file = "safetensors-0.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eed8097968585cd752a1171f86fce9aa1d89a29033e5cd8bec5a502e29f6b7af"}, + {file = "safetensors-0.4.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:880e6865cf72cb67f9ab8d04a3c4b49dd95ae92fb1583929ce65aed94e1f685f"}, + {file = "safetensors-0.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91290f83daf80ce6d1a7f629b244443c200060a80f908b29d879021409e5ea94"}, + {file = "safetensors-0.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3517d568486ab3508a7acc360b82d7a4a3e26b86efdf210a9ecd9d233c40708a"}, + {file = "safetensors-0.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f43a77eb38540f782999e5dc5645164fe9027d3f0194f6c9a5126168017efa"}, + {file = "safetensors-0.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b684d9818aa5d63fddc65f7d0151968037d255d91adf74eba82125b41c680aaa"}, + {file = "safetensors-0.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ab1f5d84185f9fefaf21413efb764e4908057b8a9a0b987ede890c353490fd70"}, + {file = "safetensors-0.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bd979642e6c3a517ef4b84ff36c2fee4015664fea05a61154fc565978347553"}, + {file = "safetensors-0.4.2-cp38-none-win32.whl", hash = "sha256:11be6e7afed29e5a5628f0aa6214e34bc194da73f558dc69fc7d56e07037422a"}, + {file = "safetensors-0.4.2-cp38-none-win_amd64.whl", hash = "sha256:2f7a6e5d29bd2cc340cffaa391fa437b1be9d21a2bd8b8724d2875d13a6ef2a9"}, + {file = "safetensors-0.4.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a5a921b4fe6925f9942adff3ebae8c16e0487908c54586a5a42f35b59fd69794"}, + {file = "safetensors-0.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b691727228c28f2d82d8a92b2bc26e7a1f129ee40b2f2a3185b5974e038ed47c"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91ca1056decc4e981248786e87b2a202d4841ee5f99d433f1adf3d44d4bcfa0e"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:55969fd2e6fdb38dc221b0ab380668c21b0efa12a7562db9924759faa3c51757"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ae429bfaecc10ab5fe78c93009b3d1656c1581da560041e700eadb497dbe7a4"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff88f194fe4ac50b463a4a6f0c03af9ad72eb5d24ec6d6730af59522e37fedb"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a80cb48d0a447f8dd18e61813efa7d3f8f8d52edf0f05806abc0c59b83431f57"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b286fb7adfee70a4189898ac2342b8a67d5f493e6b21b0af89ca8eac1b967cbf"}, + {file = "safetensors-0.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ceeff9ddbab4f78738489eb6682867ae946178776f33699737b2129b5394dc1"}, + {file = "safetensors-0.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a26fae748a7488cb3aac381eddfa818c42052c87b5e689fb4c6e82ed58cec209"}, + {file = "safetensors-0.4.2-cp39-none-win32.whl", hash = "sha256:039a42ab33c9d68b39706fd38f1922ace26866eff246bf20271edb619f5f848b"}, + {file = "safetensors-0.4.2-cp39-none-win_amd64.whl", hash = "sha256:b3a3e1f5b85859e398773f064943b62a4059f225008a2a8ee6add1edcf77cacf"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4e70d442ad17e8b153ef9095bf48ea64f15a66bf26dc2b6ca94660c154edbc24"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b90f1d9809caf4ff395951b4703295a68d12907f6945bbc3129e934ff8ae46f6"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c7ac9ad3728838006598e296b3ae9f27d80b489effd4685b92d97b3fc4c98f6"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5730d77e6ff7f4c7039e20913661ad0ea2f86c09e71c039e73dfdd1f394f08"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:44feb8cb156d6803dcd19fc6b81b27235f29b877660605a6ac35e1da7d64f0e4"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:523a241c33e7c827ab9a3a23760d75c7d062f43dfe55b6b019409f89b0fb52d1"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fb18300e8eb74291225214f26c9a8ae2110fd61a6c9b5a2ff4c4e0eb1bb9a998"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fe5437ff9fb116e44f2ab558981249ae63f978392b4576e62fcfe167d353edbc"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9304a0934ced5a5d272f39de36291dc141dfc152d277f03fb4d65f2fb2ffa7c"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:160ba1b1e11cf874602c233ab80a14f588571d09556cbc3586900121d622b5ed"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04fcd6fcf7d9c13c7e5dc7e08de5e492ee4daa8f4ad74b4d8299d3eb0224292f"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:906d14c4a677d35834fb0f3a5455ef8305e1bba10a5e0f2e0f357b3d1ad989f2"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:df3fcdec0cd543084610d1f09c65cdb10fb3079f79bceddc092b0d187c6a265b"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5ca76f13fb1cef242ea3ad2cb37388e7d005994f42af8b44bee56ba48b2d45ce"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:278a1a3414c020785decdcd741c578725721274d2f9f787fcc930882e83b89cc"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b5a461cc68ecd42d9d546e5e1268a39d8ede7934a68d1ce17c3c659cb829d6"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2341411412a41671d25e26bed59ec121e46bf4fadb8132895e610411c4b9681"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3497ac3895acf17c5f98197f1fa4769f09c5e7ede07fcb102f1c201e663e052c"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:01b5e71d3754d2201294f1eb7a6d59cce3a5702ff96d83d226571b2ca2183837"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3627dbd1ea488dd8046a0491de5087f3c0d641e7acc80c0189a33c69398f1cd1"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9d56f0ef53afad26ec54ceede78a43e9a23a076dadbbda7b44d304c591abf4c1"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b259ca73d42daf658a1bda463f1f83885ae4d93a60869be80d7f7dfcc9d8bbb5"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ebc3cd401e4eb54e7c0a70346be565e81942d9a41fafd5f4bf7ab3a55d10378"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bc384a0309b706aa0425c93abb0390508a61bf029ce99c7d9df4220f25871a5"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:af2d8f7235d8a08fbccfb8394387890e7fa38942b349a94e6eff13c52ac98087"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0911315bbcc5289087d063c2c2c7ccd711ea97a7e557a7bce005ac2cf80146aa"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1efe31673be91832d73439a2af426743e1395fc9ef7b081914e9e1d567bd7b5f"}, + {file = "safetensors-0.4.2.tar.gz", hash = "sha256:acc85dcb09ec5e8aa787f588d7ad4d55c103f31e4ff060e17d92cc0e8b8cac73"}, ] +[package.extras] +all = ["safetensors[jax]", "safetensors[numpy]", "safetensors[paddlepaddle]", "safetensors[pinned-tf]", "safetensors[quality]", "safetensors[testing]", "safetensors[torch]"] +dev = ["safetensors[all]"] +jax = ["flax (>=0.6.3)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)", "safetensors[numpy]"] +mlx = ["mlx (>=0.0.9)"] +numpy = ["numpy (>=1.21.6)"] +paddlepaddle = ["paddlepaddle (>=2.4.1)", "safetensors[numpy]"] +pinned-tf = ["safetensors[numpy]", "tensorflow (==2.11.0)"] +quality = ["black (==22.3)", "click (==8.0.4)", "flake8 (>=3.8.3)", "isort (>=5.5.4)"] +tensorflow = ["safetensors[numpy]", "tensorflow (>=2.11.0)"] +testing = ["h5py (>=3.7.0)", "huggingface_hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools_rust (>=1.5.2)"] +torch = ["safetensors[numpy]", "torch (>=1.10)"] + [[package]] name = "setuptools" version = "69.1.1" @@ -4603,7 +4968,7 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 name = "sympy" version = "1.12" description = "Computer algebra system (CAS) in Python" -optional = true +optional = false python-versions = ">=3.8" files = [ {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, @@ -4643,56 +5008,129 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] [[package]] name = "tokenizers" -version = "0.13.3" -description = "Fast and Customizable Tokenizers" -optional = true -python-versions = "*" +version = "0.15.2" +description = "" +optional = false +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.15.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:52f6130c9cbf70544287575a985bf44ae1bda2da7e8c24e97716080593638012"}, + {file = "tokenizers-0.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:054c1cc9c6d68f7ffa4e810b3d5131e0ba511b6e4be34157aa08ee54c2f8d9ee"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9b9b070fdad06e347563b88c278995735292ded1132f8657084989a4c84a6d5"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea621a7eef4b70e1f7a4e84dd989ae3f0eeb50fc8690254eacc08acb623e82f1"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf7fd9a5141634fa3aa8d6b7be362e6ae1b4cda60da81388fa533e0b552c98fd"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44f2a832cd0825295f7179eaf173381dc45230f9227ec4b44378322d900447c9"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8b9ec69247a23747669ec4b0ca10f8e3dfb3545d550258129bd62291aabe8605"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b6a4c78da863ff26dbd5ad9a8ecc33d8a8d97b535172601cf00aee9d7ce9ce"}, + {file = "tokenizers-0.15.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5ab2a4d21dcf76af60e05af8063138849eb1d6553a0d059f6534357bce8ba364"}, + {file = "tokenizers-0.15.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a47acfac7e511f6bbfcf2d3fb8c26979c780a91e06fb5b9a43831b2c0153d024"}, + {file = "tokenizers-0.15.2-cp310-none-win32.whl", hash = "sha256:064ff87bb6acdbd693666de9a4b692add41308a2c0ec0770d6385737117215f2"}, + {file = "tokenizers-0.15.2-cp310-none-win_amd64.whl", hash = "sha256:3b919afe4df7eb6ac7cafd2bd14fb507d3f408db7a68c43117f579c984a73843"}, + {file = "tokenizers-0.15.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:89cd1cb93e4b12ff39bb2d626ad77e35209de9309a71e4d3d4672667b4b256e7"}, + {file = "tokenizers-0.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cfed5c64e5be23d7ee0f0e98081a25c2a46b0b77ce99a4f0605b1ec43dd481fa"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a907d76dcfda37023ba203ab4ceeb21bc5683436ebefbd895a0841fd52f6f6f2"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20ea60479de6fc7b8ae756b4b097572372d7e4032e2521c1bbf3d90c90a99ff0"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:48e2b9335be2bc0171df9281385c2ed06a15f5cf121c44094338306ab7b33f2c"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:112a1dd436d2cc06e6ffdc0b06d55ac019a35a63afd26475205cb4b1bf0bfbff"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4620cca5c2817177ee8706f860364cc3a8845bc1e291aaf661fb899e5d1c45b0"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccd73a82751c523b3fc31ff8194702e4af4db21dc20e55b30ecc2079c5d43cb7"}, + {file = "tokenizers-0.15.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:107089f135b4ae7817affe6264f8c7a5c5b4fd9a90f9439ed495f54fcea56fb4"}, + {file = "tokenizers-0.15.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0ff110ecc57b7aa4a594396525a3451ad70988e517237fe91c540997c4e50e29"}, + {file = "tokenizers-0.15.2-cp311-none-win32.whl", hash = "sha256:6d76f00f5c32da36c61f41c58346a4fa7f0a61be02f4301fd30ad59834977cc3"}, + {file = "tokenizers-0.15.2-cp311-none-win_amd64.whl", hash = "sha256:cc90102ed17271cf0a1262babe5939e0134b3890345d11a19c3145184b706055"}, + {file = "tokenizers-0.15.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f86593c18d2e6248e72fb91c77d413a815153b8ea4e31f7cd443bdf28e467670"}, + {file = "tokenizers-0.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0774bccc6608eca23eb9d620196687c8b2360624619623cf4ba9dc9bd53e8b51"}, + {file = "tokenizers-0.15.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d0222c5b7c9b26c0b4822a82f6a7011de0a9d3060e1da176f66274b70f846b98"}, + {file = "tokenizers-0.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3835738be1de66624fff2f4f6f6684775da4e9c00bde053be7564cbf3545cc66"}, + {file = "tokenizers-0.15.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0143e7d9dcd811855c1ce1ab9bf5d96d29bf5e528fd6c7824d0465741e8c10fd"}, + {file = "tokenizers-0.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db35825f6d54215f6b6009a7ff3eedee0848c99a6271c870d2826fbbedf31a38"}, + {file = "tokenizers-0.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f5e64b0389a2be47091d8cc53c87859783b837ea1a06edd9d8e04004df55a5c"}, + {file = "tokenizers-0.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e0480c452217edd35eca56fafe2029fb4d368b7c0475f8dfa3c5c9c400a7456"}, + {file = "tokenizers-0.15.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a33ab881c8fe70474980577e033d0bc9a27b7ab8272896e500708b212995d834"}, + {file = "tokenizers-0.15.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a308a607ca9de2c64c1b9ba79ec9a403969715a1b8ba5f998a676826f1a7039d"}, + {file = "tokenizers-0.15.2-cp312-none-win32.whl", hash = "sha256:b8fcfa81bcb9447df582c5bc96a031e6df4da2a774b8080d4f02c0c16b42be0b"}, + {file = "tokenizers-0.15.2-cp312-none-win_amd64.whl", hash = "sha256:38d7ab43c6825abfc0b661d95f39c7f8af2449364f01d331f3b51c94dcff7221"}, + {file = "tokenizers-0.15.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:38bfb0204ff3246ca4d5e726e8cc8403bfc931090151e6eede54d0e0cf162ef0"}, + {file = "tokenizers-0.15.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c861d35e8286a53e06e9e28d030b5a05bcbf5ac9d7229e561e53c352a85b1fc"}, + {file = "tokenizers-0.15.2-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:936bf3842db5b2048eaa53dade907b1160f318e7c90c74bfab86f1e47720bdd6"}, + {file = "tokenizers-0.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:620beacc3373277700d0e27718aa8b25f7b383eb8001fba94ee00aeea1459d89"}, + {file = "tokenizers-0.15.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2735ecbbf37e52db4ea970e539fd2d450d213517b77745114f92867f3fc246eb"}, + {file = "tokenizers-0.15.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:473c83c5e2359bb81b0b6fde870b41b2764fcdd36d997485e07e72cc3a62264a"}, + {file = "tokenizers-0.15.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968fa1fb3c27398b28a4eca1cbd1e19355c4d3a6007f7398d48826bbe3a0f728"}, + {file = "tokenizers-0.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:865c60ae6eaebdde7da66191ee9b7db52e542ed8ee9d2c653b6d190a9351b980"}, + {file = "tokenizers-0.15.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7c0d8b52664ab2d4a8d6686eb5effc68b78608a9008f086a122a7b2996befbab"}, + {file = "tokenizers-0.15.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f33dfbdec3784093a9aebb3680d1f91336c56d86cc70ddf88708251da1fe9064"}, + {file = "tokenizers-0.15.2-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:d44ba80988ff9424e33e0a49445072ac7029d8c0e1601ad25a0ca5f41ed0c1d6"}, + {file = "tokenizers-0.15.2-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:dce74266919b892f82b1b86025a613956ea0ea62a4843d4c4237be2c5498ed3a"}, + {file = "tokenizers-0.15.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0ef06b9707baeb98b316577acb04f4852239d856b93e9ec3a299622f6084e4be"}, + {file = "tokenizers-0.15.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73e2e74bbb07910da0d37c326869f34113137b23eadad3fc00856e6b3d9930c"}, + {file = "tokenizers-0.15.2-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4eeb12daf02a59e29f578a865f55d87cd103ce62bd8a3a5874f8fdeaa82e336b"}, + {file = "tokenizers-0.15.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ba9f6895af58487ca4f54e8a664a322f16c26bbb442effd01087eba391a719e"}, + {file = "tokenizers-0.15.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ccec77aa7150e38eec6878a493bf8c263ff1fa8a62404e16c6203c64c1f16a26"}, + {file = "tokenizers-0.15.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3f40604f5042ff210ba82743dda2b6aa3e55aa12df4e9f2378ee01a17e2855e"}, + {file = "tokenizers-0.15.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5645938a42d78c4885086767c70923abad047163d809c16da75d6b290cb30bbe"}, + {file = "tokenizers-0.15.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:05a77cbfebe28a61ab5c3891f9939cc24798b63fa236d84e5f29f3a85a200c00"}, + {file = "tokenizers-0.15.2-cp37-none-win32.whl", hash = "sha256:361abdc068e8afe9c5b818769a48624687fb6aaed49636ee39bec4e95e1a215b"}, + {file = "tokenizers-0.15.2-cp37-none-win_amd64.whl", hash = "sha256:7ef789f83eb0f9baeb4d09a86cd639c0a5518528f9992f38b28e819df397eb06"}, + {file = "tokenizers-0.15.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4fe1f74a902bee74a3b25aff180fbfbf4f8b444ab37c4d496af7afd13a784ed2"}, + {file = "tokenizers-0.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c4b89038a684f40a6b15d6b09f49650ac64d951ad0f2a3ea9169687bbf2a8ba"}, + {file = "tokenizers-0.15.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d05a1b06f986d41aed5f2de464c003004b2df8aaf66f2b7628254bcbfb72a438"}, + {file = "tokenizers-0.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:508711a108684111ec8af89d3a9e9e08755247eda27d0ba5e3c50e9da1600f6d"}, + {file = "tokenizers-0.15.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:daa348f02d15160cb35439098ac96e3a53bacf35885072611cd9e5be7d333daa"}, + {file = "tokenizers-0.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:494fdbe5932d3416de2a85fc2470b797e6f3226c12845cadf054dd906afd0442"}, + {file = "tokenizers-0.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2d60f5246f4da9373f75ff18d64c69cbf60c3bca597290cea01059c336d2470"}, + {file = "tokenizers-0.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93268e788825f52de4c7bdcb6ebc1fcd4a5442c02e730faa9b6b08f23ead0e24"}, + {file = "tokenizers-0.15.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6fc7083ab404019fc9acafe78662c192673c1e696bd598d16dc005bd663a5cf9"}, + {file = "tokenizers-0.15.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:41e39b41e5531d6b2122a77532dbea60e171ef87a3820b5a3888daa847df4153"}, + {file = "tokenizers-0.15.2-cp38-none-win32.whl", hash = "sha256:06cd0487b1cbfabefb2cc52fbd6b1f8d4c37799bd6c6e1641281adaa6b2504a7"}, + {file = "tokenizers-0.15.2-cp38-none-win_amd64.whl", hash = "sha256:5179c271aa5de9c71712e31cb5a79e436ecd0d7532a408fa42a8dbfa4bc23fd9"}, + {file = "tokenizers-0.15.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82f8652a74cc107052328b87ea8b34291c0f55b96d8fb261b3880216a9f9e48e"}, + {file = "tokenizers-0.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:02458bee6f5f3139f1ebbb6d042b283af712c0981f5bc50edf771d6b762d5e4f"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c9a09cd26cca2e1c349f91aa665309ddb48d71636370749414fbf67bc83c5343"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:158be8ea8554e5ed69acc1ce3fbb23a06060bd4bbb09029431ad6b9a466a7121"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ddba9a2b0c8c81633eca0bb2e1aa5b3a15362b1277f1ae64176d0f6eba78ab1"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ef5dd1d39797044642dbe53eb2bc56435308432e9c7907728da74c69ee2adca"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:454c203164e07a860dbeb3b1f4a733be52b0edbb4dd2e5bd75023ffa8b49403a"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cf6b7f1d4dc59af960e6ffdc4faffe6460bbfa8dce27a58bf75755ffdb2526d"}, + {file = "tokenizers-0.15.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2ef09bbc16519f6c25d0c7fc0c6a33a6f62923e263c9d7cca4e58b8c61572afb"}, + {file = "tokenizers-0.15.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c9a2ebdd2ad4ec7a68e7615086e633857c85e2f18025bd05d2a4399e6c5f7169"}, + {file = "tokenizers-0.15.2-cp39-none-win32.whl", hash = "sha256:918fbb0eab96fe08e72a8c2b5461e9cce95585d82a58688e7f01c2bd546c79d0"}, + {file = "tokenizers-0.15.2-cp39-none-win_amd64.whl", hash = "sha256:524e60da0135e106b254bd71f0659be9f89d83f006ea9093ce4d1fab498c6d0d"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6a9b648a58281c4672212fab04e60648fde574877d0139cd4b4f93fe28ca8944"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7c7d18b733be6bbca8a55084027f7be428c947ddf871c500ee603e375013ffba"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:13ca3611de8d9ddfbc4dc39ef54ab1d2d4aaa114ac8727dfdc6a6ec4be017378"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:237d1bf3361cf2e6463e6c140628e6406766e8b27274f5fcc62c747ae3c6f094"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67a0fe1e49e60c664915e9fb6b0cb19bac082ab1f309188230e4b2920230edb3"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4e022fe65e99230b8fd89ebdfea138c24421f91c1a4f4781a8f5016fd5cdfb4d"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d857be2df69763362ac699f8b251a8cd3fac9d21893de129bc788f8baaef2693"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:708bb3e4283177236309e698da5fcd0879ce8fd37457d7c266d16b550bcbbd18"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:64c35e09e9899b72a76e762f9854e8750213f67567787d45f37ce06daf57ca78"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1257f4394be0d3b00de8c9e840ca5601d0a4a8438361ce9c2b05c7d25f6057b"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02272fe48280e0293a04245ca5d919b2c94a48b408b55e858feae9618138aeda"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dc3ad9ebc76eabe8b1d7c04d38be884b8f9d60c0cdc09b0aa4e3bcf746de0388"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:32e16bdeffa7c4f46bf2152172ca511808b952701d13e7c18833c0b73cb5c23f"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fb16ba563d59003028b678d2361a27f7e4ae0ab29c7a80690efa20d829c81fdb"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:2277c36d2d6cdb7876c274547921a42425b6810d38354327dd65a8009acf870c"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cf75d32e8d250781940d07f7eece253f2fe9ecdb1dc7ba6e3833fa17b82fcbc"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b3b31884dc8e9b21508bb76da80ebf7308fdb947a17affce815665d5c4d028"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b10122d8d8e30afb43bb1fe21a3619f62c3e2574bff2699cf8af8b0b6c5dc4a3"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d88b96ff0fe8e91f6ef01ba50b0d71db5017fa4e3b1d99681cec89a85faf7bf7"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:37aaec5a52e959892870a7c47cef80c53797c0db9149d458460f4f31e2fb250e"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e2ea752f2b0fe96eb6e2f3adbbf4d72aaa1272079b0dfa1145507bd6a5d537e6"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b19a808d8799fda23504a5cd31d2f58e6f52f140380082b352f877017d6342b"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:64c86e5e068ac8b19204419ed8ca90f9d25db20578f5881e337d203b314f4104"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de19c4dc503c612847edf833c82e9f73cd79926a384af9d801dcf93f110cea4e"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea09acd2fe3324174063d61ad620dec3bcf042b495515f27f638270a7d466e8b"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cf27fd43472e07b57cf420eee1e814549203d56de00b5af8659cb99885472f1f"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7ca22bd897537a0080521445d91a58886c8c04084a6a19e6c78c586e0cfa92a5"}, + {file = "tokenizers-0.15.2.tar.gz", hash = "sha256:e6e9c6e019dd5484be5beafc775ae6c925f4c69a3487040ed09b45e13df2cb91"}, ] +[package.dependencies] +huggingface_hub = ">=0.16.4,<1.0" + [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]] @@ -4706,6 +5144,75 @@ files = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +[[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 = "torch" +version = "2.2.1" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "torch-2.2.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:8d3bad336dd2c93c6bcb3268e8e9876185bda50ebde325ef211fb565c7d15273"}, + {file = "torch-2.2.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:5297f13370fdaca05959134b26a06a7f232ae254bf2e11a50eddec62525c9006"}, + {file = "torch-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f5dee8433798888ca1415055f5e3faf28a3bad660e4c29e1014acd3275ab11a"}, + {file = "torch-2.2.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:b6d78338acabf1fb2e88bf4559d837d30230cf9c3e4337261f4d83200df1fcbe"}, + {file = "torch-2.2.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:6ab3ea2e29d1aac962e905142bbe50943758f55292f1b4fdfb6f4792aae3323e"}, + {file = "torch-2.2.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:d86664ec85902967d902e78272e97d1aff1d331f7619d398d3ffab1c9b8e9157"}, + {file = "torch-2.2.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d6227060f268894f92c61af0a44c0d8212e19cb98d05c20141c73312d923bc0a"}, + {file = "torch-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:77e990af75fb1675490deb374d36e726f84732cd5677d16f19124934b2409ce9"}, + {file = "torch-2.2.1-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:46085e328d9b738c261f470231e987930f4cc9472d9ffb7087c7a1343826ac51"}, + {file = "torch-2.2.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:2d9e7e5ecbb002257cf98fae13003abbd620196c35f85c9e34c2adfb961321ec"}, + {file = "torch-2.2.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ada53aebede1c89570e56861b08d12ba4518a1f8b82d467c32665ec4d1f4b3c8"}, + {file = "torch-2.2.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:be21d4c41ecebed9e99430dac87de1439a8c7882faf23bba7fea3fea7b906ac1"}, + {file = "torch-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:79848f46196750367dcdf1d2132b722180b9d889571e14d579ae82d2f50596c5"}, + {file = "torch-2.2.1-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:7ee804847be6be0032fbd2d1e6742fea2814c92bebccb177f0d3b8e92b2d2b18"}, + {file = "torch-2.2.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:84b2fb322ab091039fdfe74e17442ff046b258eb5e513a28093152c5b07325a7"}, + {file = "torch-2.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5c0c83aa7d94569997f1f474595e808072d80b04d34912ce6f1a0e1c24b0c12a"}, + {file = "torch-2.2.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:91a1b598055ba06b2c386415d2e7f6ac818545e94c5def597a74754940188513"}, + {file = "torch-2.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f93ddf3001ecec16568390b507652644a3a103baa72de3ad3b9c530e3277098"}, + {file = "torch-2.2.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:0e8bdd4c77ac2584f33ee14c6cd3b12767b4da508ec4eed109520be7212d1069"}, + {file = "torch-2.2.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:6a21bcd7076677c97ca7db7506d683e4e9db137e8420eb4a68fb67c3668232a7"}, + {file = "torch-2.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f1b90ac61f862634039265cd0f746cc9879feee03ff962c803486301b778714b"}, + {file = "torch-2.2.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ed9e29eb94cd493b36bca9cb0b1fd7f06a0688215ad1e4b3ab4931726e0ec092"}, + {file = "torch-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:c47bc25744c743f3835831a20efdcfd60aeb7c3f9804a213f61e45803d16c2a5"}, + {file = "torch-2.2.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:0952549bcb43448c8d860d5e3e947dd18cbab491b14638e21750cb3090d5ad3e"}, + {file = "torch-2.2.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:26bd2272ec46fc62dcf7d24b2fb284d44fcb7be9d529ebf336b9860350d674ed"}, +] + +[package.dependencies] +filelock = "*" +fsspec = "*" +jinja2 = "*" +networkx = "*" +nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "8.9.2.26", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.19.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +sympy = "*" +triton = {version = "2.2.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.12\""} +typing-extensions = ">=4.8.0" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] +optree = ["optree (>=0.9.1)"] + [[package]] name = "tornado" version = "6.4" @@ -4761,6 +5268,97 @@ files = [ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +[[package]] +name = "transformers" +version = "4.38.2" +description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "transformers-4.38.2-py3-none-any.whl", hash = "sha256:c4029cb9f01b3dd335e52f364c52d2b37c65b4c78e02e6a08b1919c5c928573e"}, + {file = "transformers-4.38.2.tar.gz", hash = "sha256:c5fc7ad682b8a50a48b2a4c05d4ea2de5567adb1bdd00053619dbe5960857dd5"}, +] + +[package.dependencies] +filelock = "*" +huggingface-hub = ">=0.19.3,<1.0" +numpy = ">=1.17" +packaging = ">=20.0" +pyyaml = ">=5.1" +regex = "!=2019.12.17" +requests = "*" +safetensors = ">=0.4.1" +tokenizers = ">=0.14,<0.19" +tqdm = ">=4.27" + +[package.extras] +accelerate = ["accelerate (>=0.21.0)"] +agents = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch"] +all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision"] +audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +codecarbon = ["codecarbon (==1.2.0)"] +deepspeed = ["accelerate (>=0.21.0)", "deepspeed (>=0.9.3)"] +deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.21.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.14,<0.19)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +docs = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "hf-doc-builder", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision"] +docs-specific = ["hf-doc-builder"] +flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)"] +flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +ftfy = ["ftfy"] +integrations = ["optuna", "ray[tune] (>=2.7.0)", "sigopt"] +ja = ["fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "rhoknp (>=1.1.0,<1.3.1)", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)"] +modelcreation = ["cookiecutter (==1.7.3)"] +natten = ["natten (>=0.14.6,<0.15.0)"] +onnx = ["onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "tf2onnx"] +onnxruntime = ["onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"] +optuna = ["optuna"] +quality = ["GitPython (<3.1.19)", "datasets (!=2.5.0)", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "ruff (==0.1.5)", "urllib3 (<2.0.0)"] +ray = ["ray[tune] (>=2.7.0)"] +retrieval = ["datasets (!=2.5.0)", "faiss-cpu"] +sagemaker = ["sagemaker (>=2.31.0)"] +sentencepiece = ["protobuf", "sentencepiece (>=0.1.91,!=0.1.92)"] +serving = ["fastapi", "pydantic", "starlette", "uvicorn"] +sigopt = ["sigopt"] +sklearn = ["scikit-learn"] +speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +testing = ["GitPython (<3.1.19)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "tensorboard", "timeout-decorator"] +tf = ["keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] +tf-cpu = ["keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow-cpu (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] +tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +timm = ["timm"] +tokenizers = ["tokenizers (>=0.14,<0.19)"] +torch = ["accelerate (>=0.21.0)", "torch"] +torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] +torchhub = ["filelock", "huggingface-hub (>=0.19.3,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.14,<0.19)", "torch", "tqdm (>=4.27)"] +video = ["av (==9.2.0)", "decord (==0.6.0)"] +vision = ["Pillow (>=10.0.1,<=15.0)"] + +[[package]] +name = "triton" +version = "2.2.0" +description = "A language and compiler for custom Deep Learning operations" +optional = false +python-versions = "*" +files = [ + {file = "triton-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2294514340cfe4e8f4f9e5c66c702744c4a117d25e618bd08469d0bfed1e2e5"}, + {file = "triton-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da58a152bddb62cafa9a857dd2bc1f886dbf9f9c90a2b5da82157cd2b34392b0"}, + {file = "triton-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af58716e721460a61886668b205963dc4d1e4ac20508cc3f623aef0d70283d5"}, + {file = "triton-2.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8fe46d3ab94a8103e291bd44c741cc294b91d1d81c1a2888254cbf7ff846dab"}, + {file = "triton-2.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8ce26093e539d727e7cf6f6f0d932b1ab0574dc02567e684377630d86723ace"}, + {file = "triton-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:227cc6f357c5efcb357f3867ac2a8e7ecea2298cd4606a8ba1e931d1d5a947df"}, +] + +[package.dependencies] +filelock = "*" + +[package.extras] +build = ["cmake (>=3.20)", "lit"] +tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)", "torch"] +tutorials = ["matplotlib", "pandas", "tabulate", "torch"] + [[package]] name = "typer" version = "0.9.0" @@ -5595,4 +6193,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "233e4dfd38ce1f291ed8e966663cce04ffedfa6b0363f3c92447b23467b983e6" +content-hash = "3d584715c2e1e090a222116cc007e4c6689c475f6ccc281796a221be59b615e2" diff --git a/pyproject.toml b/pyproject.toml index adc6f2036..cb8462de1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,8 +105,11 @@ sphinx-automodapi = { version = "0.16.0", optional = true } [tool.poetry.group.dev.dependencies] pytest = "^6.2.5" +transformers = "^4.38.2" +torch = "^2.2.1" +pytest-mock = "^3.12.0" ruff = "^0.3.0" - +black = "^24.2.0" [tool.poetry.extras] chromadb = ["chromadb"] diff --git a/tests/modules/test_hf_model.py b/tests/modules/test_hf_model.py new file mode 100644 index 000000000..0b06c8042 --- /dev/null +++ b/tests/modules/test_hf_model.py @@ -0,0 +1,31 @@ +from pytest_mock.plugin import MockerFixture +from transformers import AutoModelForSeq2SeqLM + +import dspy + + +class MockConfig: + def __init__(self, architectures: list[str]): + self.architectures = architectures + + +def test_load_gated_model(mocker: MockerFixture): + conf = MockConfig(architectures=["ConditionalGeneration"]) + mocker.patch("transformers.AutoModelForSeq2SeqLM.from_pretrained") + mocker.patch("transformers.AutoConfig.from_pretrained", return_value=conf) + mocker.patch("transformers.AutoTokenizer.from_pretrained") + + some_token = "asdfasdfasdf" + model = "google/gemma-7b" + _ = dspy.HFModel(model, token=some_token) + AutoModelForSeq2SeqLM.from_pretrained.assert_called_with(model, device_map="auto", token=some_token) + + +def test_load_ungated_model(mocker: MockerFixture): + conf = MockConfig(architectures=["ConditionalGeneration"]) + mocker.patch("transformers.AutoModelForSeq2SeqLM.from_pretrained") + mocker.patch("transformers.AutoConfig.from_pretrained", return_value=conf) + mocker.patch("transformers.AutoTokenizer.from_pretrained") + _ = dspy.HFModel("openai-community/gpt2") + # no token used in automodel + AutoModelForSeq2SeqLM.from_pretrained.assert_called_with("openai-community/gpt2", device_map="auto", token=None) From fc62d608f54f3461d9b188fc36b401060945c381 Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 12:45:19 -0500 Subject: [PATCH 56/79] Update pyproject.toml --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 878601f55..4f29d0af6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ classifiers = [ ] # We have both project and tool.poetry.dependencies. Should we remove one? dependencies = [ - "anthropic~=0.18.0", "backoff~=2.2.1", "joblib~=1.3.2", "openai>=0.28.1,<2.0.0", @@ -35,6 +34,7 @@ dependencies = [ ] [project.optional-dependencies] +anthropic = ["anthropic~=0.18.0"], chromadb = ["chromadb~=0.4.14"] qdrant = ["qdrant-client~=1.6.2", "fastembed~=0.1.0"] marqo = ["marqo"] @@ -75,7 +75,6 @@ keywords = ["dspy", "ai", "language models", "llm", "openai"] [tool.poetry.dependencies] python = ">=3.9,<3.12" pydantic = "2.5.0" -anthropic = "^0.18.0" backoff = "^2.2.1" joblib = "^1.3.2" openai = "^0.28.1" @@ -86,6 +85,7 @@ tqdm = "^4.66.1" datasets = "^2.14.6" requests = "^2.31.0" optuna = "^3.4.0" +anthropic = { version = "^0.18.0", optional = true } chromadb = { version = "^0.4.14", optional = true } fastembed = { version = "^0.1.0", optional = true } marqo = { version = "*", optional = true } From e505dcdf518a4f9376cef3d3e007af28824ed0b0 Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 12:48:32 -0500 Subject: [PATCH 57/79] Update pyproject.toml (Whoops left a comma) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4f29d0af6..d31d44e18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ ] [project.optional-dependencies] -anthropic = ["anthropic~=0.18.0"], +anthropic = ["anthropic~=0.18.0"] chromadb = ["chromadb~=0.4.14"] qdrant = ["qdrant-client~=1.6.2", "fastembed~=0.1.0"] marqo = ["marqo"] From 424ee2b15c14e0c00fb49ba6c880a07b9cdc2e72 Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 12:49:24 -0500 Subject: [PATCH 58/79] Match version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d31d44e18..0637ba7fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "dspy-ai" -version = "2.3.7" +version = "2.4.1" description = "DSPy" readme = "README.md" authors = [{ name = "Omar Khattab", email = "okhattab@stanford.edu" }] From 638d8e5130014a12174e5b83c5b58eb3dd96180b Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 13:00:34 -0500 Subject: [PATCH 59/79] update linter --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0637ba7fa..713466775 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,7 +173,6 @@ exclude_lines = [ line-length = 120 indent-width = 4 target-version = "py39" -extend-unsafe-fixes = ["D"] [tool.ruff.lint] # List of rules: https://docs.astral.sh/ruff/rules From 829e573f7f5c97d9bd381ffc2b8115564071b975 Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 13:03:17 -0500 Subject: [PATCH 60/79] run ruff linter --- dsp/modules/__init__.py | 2 +- dsp/modules/anthropic.py | 12 +++++------ dsp/modules/aws_lm.py | 11 +++------- dsp/modules/azure_openai.py | 1 - dsp/modules/azurecognitivesearch.py | 10 ++++----- dsp/modules/clarifai.py | 1 + dsp/modules/cohere.py | 5 ++--- dsp/modules/finetuning/finetune_hf.py | 6 ++---- dsp/modules/google.py | 5 ++--- dsp/modules/gpt3.py | 1 - dsp/modules/hf.py | 3 +-- dsp/modules/ollama.py | 1 - dsp/modules/pyserini.py | 25 ++++++++++------------- dsp/modules/sentence_vectorizer.py | 25 +++++++++-------------- dsp/primitives/demonstrate.py | 10 +++------ dsp/primitives/predict.py | 1 - dsp/utils/ann_utils.py | 6 ++---- dsp/utils/dpr.py | 15 ++++++-------- dsp/utils/settings.py | 4 +--- dsp/utils/utils.py | 20 ++++++------------ dspy/datasets/dataset.py | 8 +++----- dspy/predict/aggregation.py | 8 +++----- dspy/predict/langchain.py | 3 ++- dspy/primitives/assertions.py | 3 +-- dspy/primitives/module.py | 4 +--- dspy/primitives/program.py | 3 +-- dspy/primitives/python_interpreter.py | 4 ++-- dspy/retrieve/chromadb_rm.py | 7 ++----- dspy/retrieve/clarifai_rm.py | 4 ++-- dspy/retrieve/databricks_rm.py | 3 +-- dspy/retrieve/deeplake_rm.py | 8 ++------ dspy/retrieve/marqo_rm.py | 3 +-- dspy/retrieve/pgvector_rm.py | 6 ++---- dspy/retrieve/pinecone_rm.py | 7 ++----- dspy/retrieve/qdrant_rm.py | 4 ++-- dspy/retrieve/vectara_rm.py | 5 +++-- dspy/retrieve/weaviate_rm.py | 5 ++--- dspy/retrieve/weaviate_rm_test.py | 3 +-- dspy/retrieve/you_rm.py | 1 - dspy/teleprompt/ensemble.py | 1 - dspy/teleprompt/signature_opt.py | 5 +++-- dspy/teleprompt/signature_opt_bayesian.py | 6 ++++-- testing/tasks/biodex.py | 19 +++++------------ 43 files changed, 105 insertions(+), 179 deletions(-) diff --git a/dsp/modules/__init__.py b/dsp/modules/__init__.py index 06e1d6f07..fdf59eabc 100644 --- a/dsp/modules/__init__.py +++ b/dsp/modules/__init__.py @@ -1,3 +1,4 @@ +from .anthropic import Claude from .azure_openai import AzureOpenAI from .bedrock import * from .cache_utils import * @@ -13,4 +14,3 @@ from .pyserini import * from .sbert import * from .sentence_vectorizer import * -from .anthropic import Claude diff --git a/dsp/modules/anthropic.py b/dsp/modules/anthropic.py index 99c9f225a..1e2617551 100644 --- a/dsp/modules/anthropic.py +++ b/dsp/modules/anthropic.py @@ -1,12 +1,11 @@ +import logging import os +from typing import Any, Optional + import backoff -import json -from typing import Optional, Any from anthropic import Anthropic, RateLimitError from dsp.modules.lm import LM -import logging - logger = logging.getLogger(__name__) @@ -23,7 +22,7 @@ def backoff_hdlr(details): def giveup_hdlr(details): - """wrapper function that decides when to give up on retry""" + """Wrapper function that decides when to give up on retry""" if "rate limits" in details.message: return False return True @@ -36,7 +35,7 @@ def __init__( model: str = "claude-instant-1.2", api_key: Optional[str] = None, api_base: Optional[str] = None, - **kwargs + **kwargs, ): super().__init__(model) self.provider = "anthropic" @@ -105,7 +104,6 @@ def __call__(self, prompt, only_completed=True, return_sorted=False, **kwargs): Returns: list[str]: list of completion choices """ - assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/aws_lm.py b/dsp/modules/aws_lm.py index a44e30a49..ee20e2c9a 100644 --- a/dsp/modules/aws_lm.py +++ b/dsp/modules/aws_lm.py @@ -1,5 +1,4 @@ -""" -A generalized AWS LLM. +"""A generalized AWS LLM. """ from __future__ import annotations @@ -17,8 +16,7 @@ class AWSLM(LM): - """ - This class adds support for an AWS model + """This class adds support for an AWS model """ def __init__( @@ -34,7 +32,6 @@ def __init__( """_summary_ Args: - service_name (str): Used in context of invoking the boto3 API. region_name (str, optional): The AWS region where this LM is hosted. model (str, optional): An LM name, e.g., a bedrock name or an AWS endpoint. @@ -101,7 +98,6 @@ def _simple_api_call(self, formatted_prompt: str, **kwargs) -> str | list[str]: def basic_request(self, prompt, **kwargs) -> str | list[str]: """Query the endpoint.""" - # Remove any texts that are too long formatted_prompt: str if self._truncate_long_prompt_prompts: @@ -166,8 +162,7 @@ def __call__( return_sorted: bool = False, **kwargs, ) -> list[str]: - """ - Query the AWS LLM. + """Query the AWS LLM. There is only support for only_completed=True and return_sorted=False right now. diff --git a/dsp/modules/azure_openai.py b/dsp/modules/azure_openai.py index c90f634e4..b9c984395 100644 --- a/dsp/modules/azure_openai.py +++ b/dsp/modules/azure_openai.py @@ -193,7 +193,6 @@ def __call__( Returns: list[dict[str, Any]]: list of completion choices """ - assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/azurecognitivesearch.py b/dsp/modules/azurecognitivesearch.py index fedc59b01..232cd24b5 100644 --- a/dsp/modules/azurecognitivesearch.py +++ b/dsp/modules/azurecognitivesearch.py @@ -44,18 +44,16 @@ def __call__(self, query: str, k: int = 10) -> Union[list[str], list[dotdict]]: return [dotdict(psg) for psg in topk] def azure_search_request(key_content: str, key_score: str, client: SearchClient, query: str, top: int =1): - ''' - Search in Azure Cognitive Search Index - ''' + """Search in Azure Cognitive Search Index + """ results = client.search(search_text=query,top=top) results = process_azure_result(results, key_content, key_content) return results def process_azure_result(results:SearchItemPaged, content_key:str, content_score: str): - ''' - process received result from Azure Cognitive Search as dictionary array and map content and score to correct format - ''' + """Process received result from Azure Cognitive Search as dictionary array and map content and score to correct format + """ res = [] for result in results: tmp = {} diff --git a/dsp/modules/clarifai.py b/dsp/modules/clarifai.py index 2d5839c62..3afc19779 100644 --- a/dsp/modules/clarifai.py +++ b/dsp/modules/clarifai.py @@ -11,6 +11,7 @@ class ClarifaiLLM(LM): model (str, optional): Clarifai URL of the model. Defaults to "Mistral-7B-Instruct". api_key (Optional[str], optional): CLARIFAI_PAT token. Defaults to None. **kwargs: Additional arguments to pass to the API provider. + Example: import dspy dspy.configure(lm=dspy.Clarifai(model=MODEL_URL, diff --git a/dsp/modules/cohere.py b/dsp/modules/cohere.py index 7308d5935..827ece89e 100644 --- a/dsp/modules/cohere.py +++ b/dsp/modules/cohere.py @@ -23,7 +23,7 @@ def backoff_hdlr(details): def giveup_hdlr(details): - """wrapper function that decides when to give up on retry""" + """Wrapper function that decides when to give up on retry""" if "rate limits" in details.message: return False return True @@ -42,8 +42,7 @@ def __init__( stop_sequences: list[str] = [], **kwargs, ): - """ - Parameters + """Parameters ---------- model : str Which pre-trained model from Cohere to use? diff --git a/dsp/modules/finetuning/finetune_hf.py b/dsp/modules/finetuning/finetune_hf.py index a22ab10fc..3ee2d0c50 100644 --- a/dsp/modules/finetuning/finetune_hf.py +++ b/dsp/modules/finetuning/finetune_hf.py @@ -229,8 +229,7 @@ def _train_seq2seq(model, tokenizer, tokenized_dataset, metric, config): def smart_tokenizer_and_embedding_resize(special_tokens_dict, tokenizer, model): - """ - Resize tokenizer and embedding. + """Resize tokenizer and embedding. Note: This is the unoptimized version that may make your embedding size not be divisible by 64. """ num_new_tokens = tokenizer.add_special_tokens(special_tokens_dict) @@ -249,8 +248,7 @@ def smart_tokenizer_and_embedding_resize(special_tokens_dict, tokenizer, model): @dataclass class DataCollatorForSupervisedDataset: - """ - Collate examples for supervised fine-tuning. + """Collate examples for supervised fine-tuning. """ tokenizer: PreTrainedTokenizer diff --git a/dsp/modules/google.py b/dsp/modules/google.py index 5d97534ea..902f46d27 100644 --- a/dsp/modules/google.py +++ b/dsp/modules/google.py @@ -25,7 +25,7 @@ def backoff_hdlr(details): def giveup_hdlr(details): - """wrapper function that decides when to give up on retry""" + """Wrapper function that decides when to give up on retry""" if "rate limits" in details.message: return False return True @@ -64,8 +64,7 @@ def __init__( safety_settings: Optional[Iterable] = BLOCK_ONLY_HIGH, **kwargs, ): - """ - Parameters + """Parameters ---------- model : str Which pre-trained model from Google to use? diff --git a/dsp/modules/gpt3.py b/dsp/modules/gpt3.py index d0b343af3..2055b0756 100644 --- a/dsp/modules/gpt3.py +++ b/dsp/modules/gpt3.py @@ -173,7 +173,6 @@ def __call__( Returns: list[dict[str, Any]]: list of completion choices """ - assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/hf.py b/dsp/modules/hf.py index aad0c0e36..54a0ad75a 100644 --- a/dsp/modules/hf.py +++ b/dsp/modules/hf.py @@ -28,7 +28,7 @@ def openai_to_hf(**kwargs): class HFModel(LM): def __init__(self, model: str, checkpoint: Optional[str] = None, is_client: bool = False, hf_device_map: Literal["auto", "balanced", "balanced_low_0", "sequential"] = "auto"): - """wrapper for Hugging Face models + """Wrapper for Hugging Face models Args: model (str): HF model identifier to load and use @@ -37,7 +37,6 @@ def __init__(self, model: str, checkpoint: Optional[str] = None, is_client: bool hf_device_map (str, optional): HF config strategy to load the model. Recommeded to use "auto", which will help loading large models using accelerate. Defaults to "auto". """ - super().__init__(model) self.provider = "hf" self.is_client = is_client diff --git a/dsp/modules/ollama.py b/dsp/modules/ollama.py index 27304d271..a28c4a646 100644 --- a/dsp/modules/ollama.py +++ b/dsp/modules/ollama.py @@ -164,7 +164,6 @@ def __call__( Returns: list[dict[str, Any]]: list of completion choices """ - assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/pyserini.py b/dsp/modules/pyserini.py index 5523a76e7..fcea328f1 100644 --- a/dsp/modules/pyserini.py +++ b/dsp/modules/pyserini.py @@ -15,21 +15,18 @@ def __init__(self, dataset: Dataset = None, id_field: str = '_id', text_fields: list[str] = ['text']) -> None: + """Args: + query_encoder (`str`): + Huggingface model to encode queries + index (`str`): + Either a prebuilt index from pyserini or a local path to a faiss index + dataset (`Dataset`): + Only required when using a local faiss index. The dataset should be the one that has been put into the faiss index. + id_field (`str`): + The name of the id field of the dataset used for retrieval. + text_fields (`list[str]`): + A list of the names of the text fields for the dataset used for retrieval. """ - Args: - - query_encoder (`str`): - Huggingface model to encode queries - index (`str`): - Either a prebuilt index from pyserini or a local path to a faiss index - dataset (`Dataset`): - Only required when using a local faiss index. The dataset should be the one that has been put into the faiss index. - id_field (`str`): - The name of the id field of the dataset used for retrieval. - text_fields (`list[str]`): - A list of the names of the text fields for the dataset used for retrieval. - """ - # Keep pyserini as an optional dependency from pyserini.prebuilt_index_info import FAISS_INDEX_INFO, IMPACT_INDEX_INFO, TF_INDEX_INFO from pyserini.search import FaissSearcher diff --git a/dsp/modules/sentence_vectorizer.py b/dsp/modules/sentence_vectorizer.py index b878420f7..25587e4a0 100644 --- a/dsp/modules/sentence_vectorizer.py +++ b/dsp/modules/sentence_vectorizer.py @@ -6,12 +6,11 @@ class BaseSentenceVectorizer(abc.ABC): - ''' - Base Class for Vectorizers. The main purpose is to vectorize text (doc/query) + """Base Class for Vectorizers. The main purpose is to vectorize text (doc/query) for ANN/KNN indexes. `__call__` method takes `List[Example]` as a single input, then extracts `field_to_vectorize` from every Example and convert them into embeddings. You can customize extraction logic in the `_extract_text_from_examples` method. - ''' + """ # embeddings will be computed based on the string in this attribute of Example object field_to_vectorize = 'text_to_vectorize' @@ -29,12 +28,11 @@ def _extract_text_from_examples(self, inp_examples: List) -> List[str]: class SentenceTransformersVectorizer(BaseSentenceVectorizer): - ''' - Vectorizer based on `SentenceTransformers` models. You can pick any model from this link: + """Vectorizer based on `SentenceTransformers` models. You can pick any model from this link: https://huggingface.co/models?library=sentence-transformers More details about models: https://www.sbert.net/docs/pretrained_models.html - ''' + """ def __init__( self, model_name_or_path: str = 'all-MiniLM-L6-v2', @@ -93,10 +91,9 @@ def __call__(self, inp_examples: List) -> np.ndarray: class NaiveGetFieldVectorizer(BaseSentenceVectorizer): - ''' - If embeddings were precomputed, then we could just extract them from the proper field + """If embeddings were precomputed, then we could just extract them from the proper field (set by `field_with_embedding`) from each `Example`. - ''' + """ def __init__(self, field_with_embedding: str = 'vectorized'): self.field_with_embedding = field_with_embedding @@ -110,12 +107,11 @@ def __call__(self, inp_examples: List["Example"]) -> np.ndarray: class CohereVectorizer(BaseSentenceVectorizer): - ''' - This vectorizer uses the Cohere API to convert texts to embeddings. + """This vectorizer uses the Cohere API to convert texts to embeddings. More about the available models: https://docs.cohere.com/reference/embed `api_key` should be passed as an argument and can be retrieved from https://dashboard.cohere.com/api-keys - ''' + """ def __init__( self, api_key: str, @@ -160,11 +156,10 @@ def __call__(self, inp_examples: List["Example"]) -> np.ndarray: class OpenAIVectorizer(BaseSentenceVectorizer): - ''' - This vectorizer uses OpenAI API to convert texts to embeddings. Changing `model` is not + """This vectorizer uses OpenAI API to convert texts to embeddings. Changing `model` is not recommended. More about the model: https://openai.com/blog/new-and-improved-embedding-model/ `api_key` should be passed as an argument or as env variable (`OPENAI_API_KEY`). - ''' + """ def __init__( self, model: str = 'text-embedding-ada-002', diff --git a/dsp/primitives/demonstrate.py b/dsp/primitives/demonstrate.py index 7dfe126b5..99a25ee35 100644 --- a/dsp/primitives/demonstrate.py +++ b/dsp/primitives/demonstrate.py @@ -90,7 +90,6 @@ def sample(train: list[Example], k: int): def all_but(train: list[Example], x: Example) -> list[Example]: """Removes the example x from the train set by comparing the question and history.""" - output = [ y for y in train @@ -127,15 +126,13 @@ def passage_has_answers(passage: str, answers: list[str]) -> bool: def cast_naive_get_only_question_text(inp_example: Example) -> Example: - """ - Extracts question as a field to vectorize with Vectorizer object. `question` field is used. + """Extracts question as a field to vectorize with Vectorizer object. `question` field is used. """ return inp_example.copy(text_to_vectorize=inp_example.question) def cast_naive_get_question_and_answer(inp_example: Example) -> Example: - """ - Extracts question and answer as fields to vectorize with Vectorizer object. + """Extracts question and answer as fields to vectorize with Vectorizer object. `question` and `answer` fields are used. They will be concatenated with the word "Answer" between. """ @@ -150,8 +147,7 @@ def knn( cast: Callable[[Example], Example] = cast_naive_get_only_question_text, **knn_args, ) -> Callable[[Example, int], list[Example]]: - """ - A function that vectorizes train data using `dsm.settings.vectorizer`, then build an ANN/KNN + """A function that vectorizes train data using `dsm.settings.vectorizer`, then build an ANN/KNN index to search similar questions among `train` samples. Args: diff --git a/dsp/primitives/predict.py b/dsp/primitives/predict.py index 41edf6c51..5aa3420f4 100644 --- a/dsp/primitives/predict.py +++ b/dsp/primitives/predict.py @@ -199,7 +199,6 @@ def majority( def majority_vote_(completions: Completions, normalize: bool, prediction_field: str): """Core logic for majority vote.""" - if not dsp.settings.lm: raise AssertionError("No LM is loaded.") diff --git a/dsp/utils/ann_utils.py b/dsp/utils/ann_utils.py index dcd3f09ce..ea0eff94c 100644 --- a/dsp/utils/ann_utils.py +++ b/dsp/utils/ann_utils.py @@ -11,8 +11,7 @@ def determine_devices(max_gpu_devices: int = 0) -> Tuple[int, bool]: - """ - Determine which device we should use + """Determine which device we should use Args: max_gpu_devices: an integer value, define how many GPUs we'll use. -1 means all devices. 0 means there are no GPUs. Default is 0. @@ -87,8 +86,7 @@ def create_faiss_index( in_list_dist_type: str = 'L2', centroid_dist_type: str = 'L2', ) -> Index: - """ - Create IVF index (with IP or L2 dist), without adding data and training + """Create IVF index (with IP or L2 dist), without adding data and training Args: emb_dim: size of each embedding n_objects: size of a trainset for index. Used to determine optimal type diff --git a/dsp/utils/dpr.py b/dsp/utils/dpr.py index d4d18f84f..8eaa231f4 100644 --- a/dsp/utils/dpr.py +++ b/dsp/utils/dpr.py @@ -1,7 +1,6 @@ -""" - Source: DPR Implementation from Facebook Research - https://github.com/facebookresearch/DPR/tree/master/dpr - Original license: https://github.com/facebookresearch/DPR/blob/main/LICENSE +"""Source: DPR Implementation from Facebook Research +https://github.com/facebookresearch/DPR/tree/master/dpr +Original license: https://github.com/facebookresearch/DPR/blob/main/LICENSE """ import unicodedata @@ -146,9 +145,8 @@ class SimpleTokenizer(Tokenizer): NON_WS = r'[^\p{Z}\p{C}]' def __init__(self, **kwargs): - """ - Args: - annotators: None or empty set (only tokenizes). + """Args: + annotators: None or empty set (only tokenizes). """ self._regexp = regex.compile( '(%s)|(%s)' % (self.ALPHA_NUM, self.NON_WS), @@ -195,8 +193,7 @@ def has_answer(tokenized_answers, text): def locate_answers(tokenized_answers, text): - """ - Returns each occurrence of an answer as (offset, endpos) in terms of *characters*. + """Returns each occurrence of an answer as (offset, endpos) in terms of *characters*. """ tokenized_text = DPR_tokenize(text) occurrences = [] diff --git a/dsp/utils/settings.py b/dsp/utils/settings.py index 1de0ada7e..a3e1e91c7 100644 --- a/dsp/utils/settings.py +++ b/dsp/utils/settings.py @@ -10,10 +10,8 @@ class Settings: _instance = None def __new__(cls): + """Singleton Pattern. See https://python-patterns.guide/gang-of-four/singleton/ """ - Singleton Pattern. See https://python-patterns.guide/gang-of-four/singleton/ - """ - if cls._instance is None: cls._instance = super().__new__(cls) cls._instance.lock = threading.Lock() diff --git a/dsp/utils/utils.py b/dsp/utils/utils.py index d5a30b0e3..69e8d812a 100644 --- a/dsp/utils/utils.py +++ b/dsp/utils/utils.py @@ -47,10 +47,8 @@ def create_directory(path): def deduplicate(seq: list[str]) -> list[str]: + """Source: https://stackoverflow.com/a/480227/1493011 """ - Source: https://stackoverflow.com/a/480227/1493011 - """ - seen = set() return [x for x in seq if not (x in seen or seen.add(x))] @@ -121,11 +119,9 @@ def flatten(L): def zipstar(L, lazy=False): - """ - A much faster A, B, C = zip(*[(a, b, c), (a, b, c), ...]) + """A much faster A, B, C = zip(*[(a, b, c), (a, b, c), ...]) May return lists or tuples. """ - if len(L) == 0: return L @@ -167,10 +163,8 @@ def groupby_first_item(lst): def process_grouped_by_first_item(lst): + """Requires items in list to already be grouped by first item. """ - Requires items in list to already be grouped by first item. - """ - groups = defaultdict(list) started = False @@ -194,12 +188,10 @@ def process_grouped_by_first_item(lst): def grouper(iterable, n, fillvalue=None): + """Collect data into fixed-length chunks or blocks + Example: grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" + Source: https://docs.python.org/3/library/itertools.html#itertools-recipes """ - Collect data into fixed-length chunks or blocks - Example: grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" - Source: https://docs.python.org/3/library/itertools.html#itertools-recipes - """ - args = [iter(iterable)] * n return itertools.zip_longest(*args, fillvalue=fillvalue) diff --git a/dspy/datasets/dataset.py b/dspy/datasets/dataset.py index c66c5edc2..69225d3b4 100644 --- a/dspy/datasets/dataset.py +++ b/dspy/datasets/dataset.py @@ -56,11 +56,9 @@ def test(self): return self._test_ def _shuffle_and_sample(self, split, data, size, seed=0): - ''' - The setting (seed=s, size=N) is always a subset - of the setting (seed=s, size=M) for N < M. - ''' - + """The setting (seed=s, size=N) is always a subset + of the setting (seed=s, size=M) for N < M. + """ data = list(data) # Shuffle the data irrespective of the requested size. diff --git a/dspy/predict/aggregation.py b/dspy/predict/aggregation.py index 4cb6df3f9..3f73ed020 100644 --- a/dspy/predict/aggregation.py +++ b/dspy/predict/aggregation.py @@ -5,12 +5,10 @@ def majority(prediction_or_completions, normalize=default_normalize, field=None): + """Returns the most common completion for the target field (or the last field) in the signature. + When normalize returns None, that completion is ignored. + In case of a tie, earlier completion are prioritized. """ - Returns the most common completion for the target field (or the last field) in the signature. - When normalize returns None, that completion is ignored. - In case of a tie, earlier completion are prioritized. - """ - assert any(isinstance(prediction_or_completions, t) for t in [Prediction, Completions, list]) input_type = type(prediction_or_completions) diff --git a/dspy/predict/langchain.py b/dspy/predict/langchain.py index 86d439f50..9cc00547c 100644 --- a/dspy/predict/langchain.py +++ b/dspy/predict/langchain.py @@ -17,7 +17,8 @@ class Template2Signature(dspy.Signature): """You are a processor for prompts. I will give you a prompt template (Python f-string) for an arbitrary task for other LMs. -Your job is to prepare three modular pieces: (i) any essential task instructions or guidelines, (ii) a list of variable names for inputs, (iv) the variable name for output.""" + Your job is to prepare three modular pieces: (i) any essential task instructions or guidelines, (ii) a list of variable names for inputs, (iv) the variable name for output. + """ template = dspy.InputField(format=lambda x: f"```\n\n{x.strip()}\n\n```\n\nLet's now prepare three modular pieces.") essential_instructions = dspy.OutputField() diff --git a/dspy/primitives/assertions.py b/dspy/primitives/assertions.py index 19f1aea3a..aba9c2492 100644 --- a/dspy/primitives/assertions.py +++ b/dspy/primitives/assertions.py @@ -326,8 +326,7 @@ def forward(self, *args, **kwargs): def assert_transform_module( module, assertion_handler=default_assertion_handler, **handler_args, ): - """ - Transform a module to handle assertions. + """Transform a module to handle assertions. """ if not getattr(module, "forward", False): raise ValueError( diff --git a/dspy/primitives/module.py b/dspy/primitives/module.py index bee80338f..9c22c799c 100644 --- a/dspy/primitives/module.py +++ b/dspy/primitives/module.py @@ -8,10 +8,8 @@ def __init__(self): pass def named_parameters(self): + """Unlike PyTorch, handles (non-recursive) lists of parameters too. """ - Unlike PyTorch, handles (non-recursive) lists of parameters too. - """ - from dspy.predict.parameter import Parameter visited = set() diff --git a/dspy/primitives/program.py b/dspy/primitives/program.py index aa499d908..de286127f 100644 --- a/dspy/primitives/program.py +++ b/dspy/primitives/program.py @@ -55,8 +55,7 @@ def map_named_predictors(self, func): return self def activate_assertions(self, handler=backtrack_handler, **handler_args): - """ - Activates assertions for the module. + """Activates assertions for the module. The default handler is the backtrack_handler. """ assert_transform_module(self, handler, **handler_args) diff --git a/dspy/primitives/python_interpreter.py b/dspy/primitives/python_interpreter.py index 1b7456c7b..8264267f1 100644 --- a/dspy/primitives/python_interpreter.py +++ b/dspy/primitives/python_interpreter.py @@ -107,7 +107,7 @@ def __init__(self, action_space: Dict[str, Any], def execute(self, code: str, state: Optional[Dict[str, Any]] = None, fuzz_state: Optional[Dict[str, Any]] = None, keep_state: bool = True) -> Any: - r""" Execute the input python codes in a security environment. + r"""Execute the input python codes in a security environment. Args: code (str): Generated python code to be executed. @@ -585,7 +585,7 @@ def execute( represents the value of the last statement (excluding "import") in the code. This value could potentially be the desired result of the LLM-generated code. - """ + """ # NOTE: Only supports Python code for now. if not interpreter: interpreter = PythonInterpreter(action_space=globals()) diff --git a/dspy/retrieve/chromadb_rm.py b/dspy/retrieve/chromadb_rm.py index 07ef407d1..f2f5aba20 100644 --- a/dspy/retrieve/chromadb_rm.py +++ b/dspy/retrieve/chromadb_rm.py @@ -1,5 +1,4 @@ -""" -Retriever model for chromadb +"""Retriever model for chromadb """ from typing import List, Optional, Union @@ -35,8 +34,7 @@ class ChromadbRM(dspy.Retrieve): - """ - A retrieval module that uses chromadb to return the top passages for a given query. + """A retrieval module that uses chromadb to return the top passages for a given query. Assumes that the chromadb index has been created and populated with the following metadata: - documents: The text of the passage @@ -94,7 +92,6 @@ def _init_chromadb( Returns: """ - self._chromadb_client = chromadb.Client( Settings( persist_directory=persist_directory, diff --git a/dspy/retrieve/clarifai_rm.py b/dspy/retrieve/clarifai_rm.py index 654234d2c..3fc132502 100644 --- a/dspy/retrieve/clarifai_rm.py +++ b/dspy/retrieve/clarifai_rm.py @@ -17,8 +17,7 @@ class ClarifaiRM(dspy.Retrieve): - """ - Retrieval module uses clarifai to return the Top K relevant pasages for the given query. + """Retrieval module uses clarifai to return the Top K relevant pasages for the given query. Assuming that you have ingested the source documents into clarifai App, where it is indexed and stored. Args: @@ -60,6 +59,7 @@ def forward( self, query_or_queries: Union[str, List[str]], k: Optional[int] = None, ) -> dspy.Prediction: """Uses clarifai-python SDK search function and retrieves top_k similar passages for given query, + Args: query_or_queries : single query or list of queries k : Top K relevant documents to return diff --git a/dspy/retrieve/databricks_rm.py b/dspy/retrieve/databricks_rm.py index c275bdddc..5fea160c7 100644 --- a/dspy/retrieve/databricks_rm.py +++ b/dspy/retrieve/databricks_rm.py @@ -9,8 +9,7 @@ class DatabricksRM(dspy.Retrieve): - """ - A retrieval module that uses Databricks Vector Search Endpoint to return the top-k embeddings for a given query. + """A retrieval module that uses Databricks Vector Search Endpoint to return the top-k embeddings for a given query. Args: databricks_index_name (str): Databricks vector search index to query diff --git a/dspy/retrieve/deeplake_rm.py b/dspy/retrieve/deeplake_rm.py index 235108a91..176cda1fc 100644 --- a/dspy/retrieve/deeplake_rm.py +++ b/dspy/retrieve/deeplake_rm.py @@ -1,5 +1,4 @@ -""" -Retriever model for deeplake +"""Retriever model for deeplake """ from collections import defaultdict @@ -23,9 +22,7 @@ class DeeplakeRM(dspy.Retrieve): - - """ - A retriever module that uses deeplake to return the top passages for a given query. + """A retriever module that uses deeplake to return the top passages for a given query. Assumes that a Deep Lake Vector Store has been created and populated with the following payload: - text: The text of the passage @@ -81,7 +78,6 @@ def embedding_function(self, texts, model="text-embedding-ada-002"): def forward( self, query_or_queries: Union[str, List[str]], k: Optional[int], ) -> dspy.Prediction: - """Search with DeepLake for self.k top passages for query Args: diff --git a/dspy/retrieve/marqo_rm.py b/dspy/retrieve/marqo_rm.py index 29c52fdb4..5ec932e6c 100644 --- a/dspy/retrieve/marqo_rm.py +++ b/dspy/retrieve/marqo_rm.py @@ -12,8 +12,7 @@ ) class MarqoRM(dspy.Retrieve): - """ - A retrieval module that uses Marqo to return the top passages for a given query. + """A retrieval module that uses Marqo to return the top passages for a given query. Assumes that a Marqo index has been created and populated with the following payload: - document: The text of the passage diff --git a/dspy/retrieve/pgvector_rm.py b/dspy/retrieve/pgvector_rm.py index cf1773f17..295461b5a 100644 --- a/dspy/retrieve/pgvector_rm.py +++ b/dspy/retrieve/pgvector_rm.py @@ -15,8 +15,7 @@ class PgVectorRM(dspy.Retrieve): - """ - Implements a retriever that (as the name suggests) uses pgvector to retrieve passages, + """Implements a retriever that (as the name suggests) uses pgvector to retrieve passages, using a raw SQL query and a postgresql connection managed by psycopg2. It needs to register the pgvector extension with the psycopg2 connection @@ -65,8 +64,7 @@ def __init__( embedding_field: str = "embedding", fields: List[str] = ['text'], ): - """ - k = 20 is the number of paragraphs to retrieve + """K = 20 is the number of paragraphs to retrieve """ self.openai_client = openai_client diff --git a/dspy/retrieve/pinecone_rm.py b/dspy/retrieve/pinecone_rm.py index 0328bc6ba..70589a0f6 100644 --- a/dspy/retrieve/pinecone_rm.py +++ b/dspy/retrieve/pinecone_rm.py @@ -1,5 +1,4 @@ -""" -Retriever model for Pinecone +"""Retriever model for Pinecone Author: Dhar Rawal (@drawal1) """ @@ -34,8 +33,7 @@ ERRORS = (openai.RateLimitError, openai.APIError) class PineconeRM(dspy.Retrieve): - """ - A retrieval module that uses Pinecone to return the top passages for a given query. + """A retrieval module that uses Pinecone to return the top passages for a given query. Assumes that the Pinecone index has been created and populated with the following metadata: - text: The text of the passage @@ -135,7 +133,6 @@ def _init_pinecone( Returns: pinecone.Index: The loaded index. """ - # Pinecone init overrides default if kwargs are present, so we need to exclude if None kwargs = {} if api_key: diff --git a/dspy/retrieve/qdrant_rm.py b/dspy/retrieve/qdrant_rm.py index 5c2af050b..7ddaa47b7 100644 --- a/dspy/retrieve/qdrant_rm.py +++ b/dspy/retrieve/qdrant_rm.py @@ -14,8 +14,7 @@ class QdrantRM(dspy.Retrieve): - """ - A retrieval module that uses Qdrant to return the top passages for a given query. + """A retrieval module that uses Qdrant to return the top passages for a given query. Assumes that a Qdrant collection has been created and populated with the following payload: - document: The text of the passage @@ -59,6 +58,7 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> Args: query_or_queries (Union[str, List[str]]): The query or queries to search for. k (Optional[int]): The number of top passages to retrieve. Defaults to self.k. + Returns: dspy.Prediction: An object containing the retrieved passages. """ diff --git a/dspy/retrieve/vectara_rm.py b/dspy/retrieve/vectara_rm.py index 047c70d6c..889993520 100644 --- a/dspy/retrieve/vectara_rm.py +++ b/dspy/retrieve/vectara_rm.py @@ -15,8 +15,7 @@ def remove_snippet(s: str) -> str: return s.replace(START_SNIPPET, "").replace(END_SNIPPET, "") class VectaraRM(dspy.Retrieve): - """ - A retrieval module that uses Vectara to return the top passages for a given query. + """A retrieval module that uses Vectara to return the top passages for a given query. Assumes that a Vectara corpus has been created and populated with the following payload: - document: The text of the passage @@ -70,6 +69,7 @@ def _vectara_query( limit: int = 3, ) -> List[str]: """Query Vectara index to get for top k matching passages. + Args: query: query string """ @@ -135,6 +135,7 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> Args: query_or_queries (Union[str, List[str]]): The query or queries to search for. k (Optional[int]): The number of top passages to retrieve. Defaults to self.k. + Returns: dspy.Prediction: An object containing the retrieved passages. """ diff --git a/dspy/retrieve/weaviate_rm.py b/dspy/retrieve/weaviate_rm.py index 61e8d1ef0..4951032aa 100644 --- a/dspy/retrieve/weaviate_rm.py +++ b/dspy/retrieve/weaviate_rm.py @@ -12,8 +12,7 @@ class WeaviateRM(dspy.Retrieve): - """ - A retrieval module that uses Weaviate to return the top passages for a given query. + """A retrieval module that uses Weaviate to return the top passages for a given query. Assumes that a Weaviate collection has been created and populated with the following payload: - content: The text of the passage @@ -59,10 +58,10 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> Args: query_or_queries (Union[str, List[str]]): The query or queries to search for. k (Optional[int]): The number of top passages to retrieve. Defaults to self.k. + Returns: dspy.Prediction: An object containing the retrieved passages. """ - k = k if k is not None else self.k queries = ( [query_or_queries] diff --git a/dspy/retrieve/weaviate_rm_test.py b/dspy/retrieve/weaviate_rm_test.py index fa2c97237..d638639b2 100644 --- a/dspy/retrieve/weaviate_rm_test.py +++ b/dspy/retrieve/weaviate_rm_test.py @@ -7,8 +7,7 @@ # Connect DSPy # Test this API -""" -from dspy.retrieve.weaviate_rm import WeaviateRM +"""from dspy.retrieve.weaviate_rm import WeaviateRM retriever_model = WeaviateRM("WeaviateBlogChunk", weaviate_client=weaviate_client) dspy.settings.configure(rm=retriever_model) diff --git a/dspy/retrieve/you_rm.py b/dspy/retrieve/you_rm.py index 25a62ccea..8534a3645 100644 --- a/dspy/retrieve/you_rm.py +++ b/dspy/retrieve/you_rm.py @@ -27,7 +27,6 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int] = No Returns: dspy.Prediction: An object containing the retrieved passages. """ - k = k if k is not None else self.k queries = ( diff --git a/dspy/teleprompt/ensemble.py b/dspy/teleprompt/ensemble.py index 5e0db9bca..7ed13deb4 100644 --- a/dspy/teleprompt/ensemble.py +++ b/dspy/teleprompt/ensemble.py @@ -9,7 +9,6 @@ class Ensemble(Teleprompter): def __init__(self, *, reduce_fn=None, size=None, deterministic=False): """A common reduce_fn is dspy.majority.""" - assert deterministic is False, "TODO: Implement example hashing for deterministic ensemble." self.reduce_fn = reduce_fn diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index d71aa69a7..47789ae9f 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -41,7 +41,8 @@ class BasicGenerateInstruction(Signature): class GenerateInstructionGivenAttempts(dspy.Signature): """You are an instruction optimizer for large language models. I will give some task instructions I've tried, along with their corresponding validation scores. The instructions are arranged in increasing order based on their scores, where higher scores indicate better quality. -Your task is to propose a new instruction that will lead a good language model to perform the task even better. Don't be afraid to be creative.""" + Your task is to propose a new instruction that will lead a good language model to perform the task even better. Don't be afraid to be creative. + """ attempted_instructions = dspy.InputField(format=dsp.passages2text) proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") @@ -101,7 +102,7 @@ def _print_signature(self, predictor): def compile(self, student, *, devset, eval_kwargs): - """student is a program that needs to be optimized, note that it may be zero-shot or already pre-optimized for demos != []""" + """Student is a program that needs to be optimized, note that it may be zero-shot or already pre-optimized for demos != []""" module = student.deepcopy() evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) total_calls = 0 diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index e316462c9..87fc9ad4e 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -58,7 +58,8 @@ class BasicGenerateInstructionWithDataObservations(Signature): class BasicGenerateInstructionWithExamples(dspy.Signature): ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``examples`` of the expected inputs and outputs. -Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""") + Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative. + """) # attempted_instructions = dspy.InputField(format=str, desc="Previously attempted task instructions, along with their resulting validation score, and an example of the instruction in use on a sample from our dataset.") basic_instruction = dspy.InputField(desc="The initial instructions before optimization") # examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") @@ -69,7 +70,8 @@ class BasicGenerateInstructionWithExamples(dspy.Signature): class BasicGenerateInstructionWithExamplesAndDataObservations(dspy.Signature): ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``observations`` I have made about the dataset and task, along with some ``examples`` of the expected inputs and outputs. -Your task is to propose a new improved instruction and prefix for the output field that will lead a good language model to perform the task well. Don't be afraid to be creative.""") + Your task is to propose a new improved instruction and prefix for the output field that will lead a good language model to perform the task well. Don't be afraid to be creative. + """) basic_instruction = dspy.InputField(desc="The initial instructions before optimization") observations = dspy.InputField(desc="Observations about the dataset and task") examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") diff --git a/testing/tasks/biodex.py b/testing/tasks/biodex.py index 6e51745b3..79d4bb84d 100644 --- a/testing/tasks/biodex.py +++ b/testing/tasks/biodex.py @@ -365,10 +365,8 @@ def base_ground(reaction, K): @lru_cache(maxsize=100000) def ground_v1(reaction, K=3): + """Prefers exact matches over fuzzy matches, when available. """ - Prefers exact matches over fuzzy matches, when available. - """ - exact_matches, fuzzy_matches = base_ground(reaction, K) matches = exact_matches[:1] or fuzzy_matches @@ -379,10 +377,8 @@ def ground_v1(reaction, K=3): @lru_cache(maxsize=100000) def ground_v2(reaction, K=1): + """When K=1 (default), returns exact matches (if available) or the best fuzzy match. """ - When K=1 (default), returns exact matches (if available) or the best fuzzy match. - """ - exact_matches, fuzzy_matches = base_ground(reaction, K) matches = [(match.score / 100.0, match.node.term) for match in (exact_matches[:1] + fuzzy_matches)] @@ -395,8 +391,7 @@ def ground_v2(reaction, K=1): @lru_cache(maxsize=100000) def ground_v4(reaction, K=3): - """ - Returns the best three matches (including one exact match, if available) and applies a prior. + """Returns the best three matches (including one exact match, if available) and applies a prior. """ exact_matches, fuzzy_matches = base_ground(reaction, K) @@ -408,10 +403,8 @@ def ground_v4(reaction, K=3): @lru_cache(maxsize=100000) def ground_v4b(reaction, K=3): + """Returns the best three matches (including one exact match, if available) and applies a prior. """ - Returns the best three matches (including one exact match, if available) and applies a prior. - """ - exact_matches, fuzzy_matches = base_ground(reaction, K) matches = [((match.score / 100.0) * math.log(match.node.count + 0.1), match.node.term) @@ -422,10 +415,8 @@ def ground_v4b(reaction, K=3): @lru_cache(maxsize=100000) def ground_v4c(reaction, K=3): + """Returns the best three matches (including one exact match, if available) and applies a prior. """ - Returns the best three matches (including one exact match, if available) and applies a prior. - """ - exact_matches, fuzzy_matches = base_ground(reaction, K) matches = [((match.score / 100.0) * (match.node.count + 0.1), match.node.term) From 79e3187a9f9b15f431b49bbb1691127d990a1b3d Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 13:05:46 -0500 Subject: [PATCH 61/79] update --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 713466775..2516f5d98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ ] [project.optional-dependencies] -anthropic = ["anthropic~=0.18.0"] +anthropic = ["anthropic~=0.18.0"], chromadb = ["chromadb~=0.4.14"] qdrant = ["qdrant-client~=1.6.2", "fastembed~=0.1.0"] marqo = ["marqo"] From 275f133dc9b8c30eb327afd584487f0114cbaf13 Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 13:06:35 -0500 Subject: [PATCH 62/79] Revert "run ruff linter" This reverts commit 829e573f7f5c97d9bd381ffc2b8115564071b975. --- dsp/modules/__init__.py | 2 +- dsp/modules/anthropic.py | 12 ++++++----- dsp/modules/aws_lm.py | 11 +++++++--- dsp/modules/azure_openai.py | 1 + dsp/modules/azurecognitivesearch.py | 10 +++++---- dsp/modules/clarifai.py | 1 - dsp/modules/cohere.py | 5 +++-- dsp/modules/finetuning/finetune_hf.py | 6 ++++-- dsp/modules/google.py | 5 +++-- dsp/modules/gpt3.py | 1 + dsp/modules/hf.py | 3 ++- dsp/modules/ollama.py | 1 + dsp/modules/pyserini.py | 25 +++++++++++++---------- dsp/modules/sentence_vectorizer.py | 25 ++++++++++++++--------- dsp/primitives/demonstrate.py | 10 ++++++--- dsp/primitives/predict.py | 1 + dsp/utils/ann_utils.py | 6 ++++-- dsp/utils/dpr.py | 15 ++++++++------ dsp/utils/settings.py | 4 +++- dsp/utils/utils.py | 20 ++++++++++++------ dspy/datasets/dataset.py | 8 +++++--- dspy/predict/aggregation.py | 8 +++++--- dspy/predict/langchain.py | 3 +-- dspy/primitives/assertions.py | 3 ++- dspy/primitives/module.py | 4 +++- dspy/primitives/program.py | 3 ++- dspy/primitives/python_interpreter.py | 4 ++-- dspy/retrieve/chromadb_rm.py | 7 +++++-- dspy/retrieve/clarifai_rm.py | 4 ++-- dspy/retrieve/databricks_rm.py | 3 ++- dspy/retrieve/deeplake_rm.py | 8 ++++++-- dspy/retrieve/marqo_rm.py | 3 ++- dspy/retrieve/pgvector_rm.py | 6 ++++-- dspy/retrieve/pinecone_rm.py | 7 +++++-- dspy/retrieve/qdrant_rm.py | 4 ++-- dspy/retrieve/vectara_rm.py | 5 ++--- dspy/retrieve/weaviate_rm.py | 5 +++-- dspy/retrieve/weaviate_rm_test.py | 3 ++- dspy/retrieve/you_rm.py | 1 + dspy/teleprompt/ensemble.py | 1 + dspy/teleprompt/signature_opt.py | 5 ++--- dspy/teleprompt/signature_opt_bayesian.py | 6 ++---- testing/tasks/biodex.py | 19 ++++++++++++----- 43 files changed, 179 insertions(+), 105 deletions(-) diff --git a/dsp/modules/__init__.py b/dsp/modules/__init__.py index fdf59eabc..06e1d6f07 100644 --- a/dsp/modules/__init__.py +++ b/dsp/modules/__init__.py @@ -1,4 +1,3 @@ -from .anthropic import Claude from .azure_openai import AzureOpenAI from .bedrock import * from .cache_utils import * @@ -14,3 +13,4 @@ from .pyserini import * from .sbert import * from .sentence_vectorizer import * +from .anthropic import Claude diff --git a/dsp/modules/anthropic.py b/dsp/modules/anthropic.py index 1e2617551..99c9f225a 100644 --- a/dsp/modules/anthropic.py +++ b/dsp/modules/anthropic.py @@ -1,11 +1,12 @@ -import logging import os -from typing import Any, Optional - import backoff +import json +from typing import Optional, Any from anthropic import Anthropic, RateLimitError from dsp.modules.lm import LM +import logging + logger = logging.getLogger(__name__) @@ -22,7 +23,7 @@ def backoff_hdlr(details): def giveup_hdlr(details): - """Wrapper function that decides when to give up on retry""" + """wrapper function that decides when to give up on retry""" if "rate limits" in details.message: return False return True @@ -35,7 +36,7 @@ def __init__( model: str = "claude-instant-1.2", api_key: Optional[str] = None, api_base: Optional[str] = None, - **kwargs, + **kwargs ): super().__init__(model) self.provider = "anthropic" @@ -104,6 +105,7 @@ def __call__(self, prompt, only_completed=True, return_sorted=False, **kwargs): Returns: list[str]: list of completion choices """ + assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/aws_lm.py b/dsp/modules/aws_lm.py index ee20e2c9a..a44e30a49 100644 --- a/dsp/modules/aws_lm.py +++ b/dsp/modules/aws_lm.py @@ -1,4 +1,5 @@ -"""A generalized AWS LLM. +""" +A generalized AWS LLM. """ from __future__ import annotations @@ -16,7 +17,8 @@ class AWSLM(LM): - """This class adds support for an AWS model + """ + This class adds support for an AWS model """ def __init__( @@ -32,6 +34,7 @@ def __init__( """_summary_ Args: + service_name (str): Used in context of invoking the boto3 API. region_name (str, optional): The AWS region where this LM is hosted. model (str, optional): An LM name, e.g., a bedrock name or an AWS endpoint. @@ -98,6 +101,7 @@ def _simple_api_call(self, formatted_prompt: str, **kwargs) -> str | list[str]: def basic_request(self, prompt, **kwargs) -> str | list[str]: """Query the endpoint.""" + # Remove any texts that are too long formatted_prompt: str if self._truncate_long_prompt_prompts: @@ -162,7 +166,8 @@ def __call__( return_sorted: bool = False, **kwargs, ) -> list[str]: - """Query the AWS LLM. + """ + Query the AWS LLM. There is only support for only_completed=True and return_sorted=False right now. diff --git a/dsp/modules/azure_openai.py b/dsp/modules/azure_openai.py index b9c984395..c90f634e4 100644 --- a/dsp/modules/azure_openai.py +++ b/dsp/modules/azure_openai.py @@ -193,6 +193,7 @@ def __call__( Returns: list[dict[str, Any]]: list of completion choices """ + assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/azurecognitivesearch.py b/dsp/modules/azurecognitivesearch.py index 232cd24b5..fedc59b01 100644 --- a/dsp/modules/azurecognitivesearch.py +++ b/dsp/modules/azurecognitivesearch.py @@ -44,16 +44,18 @@ def __call__(self, query: str, k: int = 10) -> Union[list[str], list[dotdict]]: return [dotdict(psg) for psg in topk] def azure_search_request(key_content: str, key_score: str, client: SearchClient, query: str, top: int =1): - """Search in Azure Cognitive Search Index - """ + ''' + Search in Azure Cognitive Search Index + ''' results = client.search(search_text=query,top=top) results = process_azure_result(results, key_content, key_content) return results def process_azure_result(results:SearchItemPaged, content_key:str, content_score: str): - """Process received result from Azure Cognitive Search as dictionary array and map content and score to correct format - """ + ''' + process received result from Azure Cognitive Search as dictionary array and map content and score to correct format + ''' res = [] for result in results: tmp = {} diff --git a/dsp/modules/clarifai.py b/dsp/modules/clarifai.py index 3afc19779..2d5839c62 100644 --- a/dsp/modules/clarifai.py +++ b/dsp/modules/clarifai.py @@ -11,7 +11,6 @@ class ClarifaiLLM(LM): model (str, optional): Clarifai URL of the model. Defaults to "Mistral-7B-Instruct". api_key (Optional[str], optional): CLARIFAI_PAT token. Defaults to None. **kwargs: Additional arguments to pass to the API provider. - Example: import dspy dspy.configure(lm=dspy.Clarifai(model=MODEL_URL, diff --git a/dsp/modules/cohere.py b/dsp/modules/cohere.py index 827ece89e..7308d5935 100644 --- a/dsp/modules/cohere.py +++ b/dsp/modules/cohere.py @@ -23,7 +23,7 @@ def backoff_hdlr(details): def giveup_hdlr(details): - """Wrapper function that decides when to give up on retry""" + """wrapper function that decides when to give up on retry""" if "rate limits" in details.message: return False return True @@ -42,7 +42,8 @@ def __init__( stop_sequences: list[str] = [], **kwargs, ): - """Parameters + """ + Parameters ---------- model : str Which pre-trained model from Cohere to use? diff --git a/dsp/modules/finetuning/finetune_hf.py b/dsp/modules/finetuning/finetune_hf.py index 3ee2d0c50..a22ab10fc 100644 --- a/dsp/modules/finetuning/finetune_hf.py +++ b/dsp/modules/finetuning/finetune_hf.py @@ -229,7 +229,8 @@ def _train_seq2seq(model, tokenizer, tokenized_dataset, metric, config): def smart_tokenizer_and_embedding_resize(special_tokens_dict, tokenizer, model): - """Resize tokenizer and embedding. + """ + Resize tokenizer and embedding. Note: This is the unoptimized version that may make your embedding size not be divisible by 64. """ num_new_tokens = tokenizer.add_special_tokens(special_tokens_dict) @@ -248,7 +249,8 @@ def smart_tokenizer_and_embedding_resize(special_tokens_dict, tokenizer, model): @dataclass class DataCollatorForSupervisedDataset: - """Collate examples for supervised fine-tuning. + """ + Collate examples for supervised fine-tuning. """ tokenizer: PreTrainedTokenizer diff --git a/dsp/modules/google.py b/dsp/modules/google.py index 902f46d27..5d97534ea 100644 --- a/dsp/modules/google.py +++ b/dsp/modules/google.py @@ -25,7 +25,7 @@ def backoff_hdlr(details): def giveup_hdlr(details): - """Wrapper function that decides when to give up on retry""" + """wrapper function that decides when to give up on retry""" if "rate limits" in details.message: return False return True @@ -64,7 +64,8 @@ def __init__( safety_settings: Optional[Iterable] = BLOCK_ONLY_HIGH, **kwargs, ): - """Parameters + """ + Parameters ---------- model : str Which pre-trained model from Google to use? diff --git a/dsp/modules/gpt3.py b/dsp/modules/gpt3.py index 2055b0756..d0b343af3 100644 --- a/dsp/modules/gpt3.py +++ b/dsp/modules/gpt3.py @@ -173,6 +173,7 @@ def __call__( Returns: list[dict[str, Any]]: list of completion choices """ + assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/hf.py b/dsp/modules/hf.py index 54a0ad75a..aad0c0e36 100644 --- a/dsp/modules/hf.py +++ b/dsp/modules/hf.py @@ -28,7 +28,7 @@ def openai_to_hf(**kwargs): class HFModel(LM): def __init__(self, model: str, checkpoint: Optional[str] = None, is_client: bool = False, hf_device_map: Literal["auto", "balanced", "balanced_low_0", "sequential"] = "auto"): - """Wrapper for Hugging Face models + """wrapper for Hugging Face models Args: model (str): HF model identifier to load and use @@ -37,6 +37,7 @@ def __init__(self, model: str, checkpoint: Optional[str] = None, is_client: bool hf_device_map (str, optional): HF config strategy to load the model. Recommeded to use "auto", which will help loading large models using accelerate. Defaults to "auto". """ + super().__init__(model) self.provider = "hf" self.is_client = is_client diff --git a/dsp/modules/ollama.py b/dsp/modules/ollama.py index a28c4a646..27304d271 100644 --- a/dsp/modules/ollama.py +++ b/dsp/modules/ollama.py @@ -164,6 +164,7 @@ def __call__( Returns: list[dict[str, Any]]: list of completion choices """ + assert only_completed, "for now" assert return_sorted is False, "for now" diff --git a/dsp/modules/pyserini.py b/dsp/modules/pyserini.py index fcea328f1..5523a76e7 100644 --- a/dsp/modules/pyserini.py +++ b/dsp/modules/pyserini.py @@ -15,18 +15,21 @@ def __init__(self, dataset: Dataset = None, id_field: str = '_id', text_fields: list[str] = ['text']) -> None: - """Args: - query_encoder (`str`): - Huggingface model to encode queries - index (`str`): - Either a prebuilt index from pyserini or a local path to a faiss index - dataset (`Dataset`): - Only required when using a local faiss index. The dataset should be the one that has been put into the faiss index. - id_field (`str`): - The name of the id field of the dataset used for retrieval. - text_fields (`list[str]`): - A list of the names of the text fields for the dataset used for retrieval. """ + Args: + + query_encoder (`str`): + Huggingface model to encode queries + index (`str`): + Either a prebuilt index from pyserini or a local path to a faiss index + dataset (`Dataset`): + Only required when using a local faiss index. The dataset should be the one that has been put into the faiss index. + id_field (`str`): + The name of the id field of the dataset used for retrieval. + text_fields (`list[str]`): + A list of the names of the text fields for the dataset used for retrieval. + """ + # Keep pyserini as an optional dependency from pyserini.prebuilt_index_info import FAISS_INDEX_INFO, IMPACT_INDEX_INFO, TF_INDEX_INFO from pyserini.search import FaissSearcher diff --git a/dsp/modules/sentence_vectorizer.py b/dsp/modules/sentence_vectorizer.py index 25587e4a0..b878420f7 100644 --- a/dsp/modules/sentence_vectorizer.py +++ b/dsp/modules/sentence_vectorizer.py @@ -6,11 +6,12 @@ class BaseSentenceVectorizer(abc.ABC): - """Base Class for Vectorizers. The main purpose is to vectorize text (doc/query) + ''' + Base Class for Vectorizers. The main purpose is to vectorize text (doc/query) for ANN/KNN indexes. `__call__` method takes `List[Example]` as a single input, then extracts `field_to_vectorize` from every Example and convert them into embeddings. You can customize extraction logic in the `_extract_text_from_examples` method. - """ + ''' # embeddings will be computed based on the string in this attribute of Example object field_to_vectorize = 'text_to_vectorize' @@ -28,11 +29,12 @@ def _extract_text_from_examples(self, inp_examples: List) -> List[str]: class SentenceTransformersVectorizer(BaseSentenceVectorizer): - """Vectorizer based on `SentenceTransformers` models. You can pick any model from this link: + ''' + Vectorizer based on `SentenceTransformers` models. You can pick any model from this link: https://huggingface.co/models?library=sentence-transformers More details about models: https://www.sbert.net/docs/pretrained_models.html - """ + ''' def __init__( self, model_name_or_path: str = 'all-MiniLM-L6-v2', @@ -91,9 +93,10 @@ def __call__(self, inp_examples: List) -> np.ndarray: class NaiveGetFieldVectorizer(BaseSentenceVectorizer): - """If embeddings were precomputed, then we could just extract them from the proper field + ''' + If embeddings were precomputed, then we could just extract them from the proper field (set by `field_with_embedding`) from each `Example`. - """ + ''' def __init__(self, field_with_embedding: str = 'vectorized'): self.field_with_embedding = field_with_embedding @@ -107,11 +110,12 @@ def __call__(self, inp_examples: List["Example"]) -> np.ndarray: class CohereVectorizer(BaseSentenceVectorizer): - """This vectorizer uses the Cohere API to convert texts to embeddings. + ''' + This vectorizer uses the Cohere API to convert texts to embeddings. More about the available models: https://docs.cohere.com/reference/embed `api_key` should be passed as an argument and can be retrieved from https://dashboard.cohere.com/api-keys - """ + ''' def __init__( self, api_key: str, @@ -156,10 +160,11 @@ def __call__(self, inp_examples: List["Example"]) -> np.ndarray: class OpenAIVectorizer(BaseSentenceVectorizer): - """This vectorizer uses OpenAI API to convert texts to embeddings. Changing `model` is not + ''' + This vectorizer uses OpenAI API to convert texts to embeddings. Changing `model` is not recommended. More about the model: https://openai.com/blog/new-and-improved-embedding-model/ `api_key` should be passed as an argument or as env variable (`OPENAI_API_KEY`). - """ + ''' def __init__( self, model: str = 'text-embedding-ada-002', diff --git a/dsp/primitives/demonstrate.py b/dsp/primitives/demonstrate.py index 99a25ee35..7dfe126b5 100644 --- a/dsp/primitives/demonstrate.py +++ b/dsp/primitives/demonstrate.py @@ -90,6 +90,7 @@ def sample(train: list[Example], k: int): def all_but(train: list[Example], x: Example) -> list[Example]: """Removes the example x from the train set by comparing the question and history.""" + output = [ y for y in train @@ -126,13 +127,15 @@ def passage_has_answers(passage: str, answers: list[str]) -> bool: def cast_naive_get_only_question_text(inp_example: Example) -> Example: - """Extracts question as a field to vectorize with Vectorizer object. `question` field is used. + """ + Extracts question as a field to vectorize with Vectorizer object. `question` field is used. """ return inp_example.copy(text_to_vectorize=inp_example.question) def cast_naive_get_question_and_answer(inp_example: Example) -> Example: - """Extracts question and answer as fields to vectorize with Vectorizer object. + """ + Extracts question and answer as fields to vectorize with Vectorizer object. `question` and `answer` fields are used. They will be concatenated with the word "Answer" between. """ @@ -147,7 +150,8 @@ def knn( cast: Callable[[Example], Example] = cast_naive_get_only_question_text, **knn_args, ) -> Callable[[Example, int], list[Example]]: - """A function that vectorizes train data using `dsm.settings.vectorizer`, then build an ANN/KNN + """ + A function that vectorizes train data using `dsm.settings.vectorizer`, then build an ANN/KNN index to search similar questions among `train` samples. Args: diff --git a/dsp/primitives/predict.py b/dsp/primitives/predict.py index 5aa3420f4..41edf6c51 100644 --- a/dsp/primitives/predict.py +++ b/dsp/primitives/predict.py @@ -199,6 +199,7 @@ def majority( def majority_vote_(completions: Completions, normalize: bool, prediction_field: str): """Core logic for majority vote.""" + if not dsp.settings.lm: raise AssertionError("No LM is loaded.") diff --git a/dsp/utils/ann_utils.py b/dsp/utils/ann_utils.py index ea0eff94c..dcd3f09ce 100644 --- a/dsp/utils/ann_utils.py +++ b/dsp/utils/ann_utils.py @@ -11,7 +11,8 @@ def determine_devices(max_gpu_devices: int = 0) -> Tuple[int, bool]: - """Determine which device we should use + """ + Determine which device we should use Args: max_gpu_devices: an integer value, define how many GPUs we'll use. -1 means all devices. 0 means there are no GPUs. Default is 0. @@ -86,7 +87,8 @@ def create_faiss_index( in_list_dist_type: str = 'L2', centroid_dist_type: str = 'L2', ) -> Index: - """Create IVF index (with IP or L2 dist), without adding data and training + """ + Create IVF index (with IP or L2 dist), without adding data and training Args: emb_dim: size of each embedding n_objects: size of a trainset for index. Used to determine optimal type diff --git a/dsp/utils/dpr.py b/dsp/utils/dpr.py index 8eaa231f4..d4d18f84f 100644 --- a/dsp/utils/dpr.py +++ b/dsp/utils/dpr.py @@ -1,6 +1,7 @@ -"""Source: DPR Implementation from Facebook Research -https://github.com/facebookresearch/DPR/tree/master/dpr -Original license: https://github.com/facebookresearch/DPR/blob/main/LICENSE +""" + Source: DPR Implementation from Facebook Research + https://github.com/facebookresearch/DPR/tree/master/dpr + Original license: https://github.com/facebookresearch/DPR/blob/main/LICENSE """ import unicodedata @@ -145,8 +146,9 @@ class SimpleTokenizer(Tokenizer): NON_WS = r'[^\p{Z}\p{C}]' def __init__(self, **kwargs): - """Args: - annotators: None or empty set (only tokenizes). + """ + Args: + annotators: None or empty set (only tokenizes). """ self._regexp = regex.compile( '(%s)|(%s)' % (self.ALPHA_NUM, self.NON_WS), @@ -193,7 +195,8 @@ def has_answer(tokenized_answers, text): def locate_answers(tokenized_answers, text): - """Returns each occurrence of an answer as (offset, endpos) in terms of *characters*. + """ + Returns each occurrence of an answer as (offset, endpos) in terms of *characters*. """ tokenized_text = DPR_tokenize(text) occurrences = [] diff --git a/dsp/utils/settings.py b/dsp/utils/settings.py index a3e1e91c7..1de0ada7e 100644 --- a/dsp/utils/settings.py +++ b/dsp/utils/settings.py @@ -10,8 +10,10 @@ class Settings: _instance = None def __new__(cls): - """Singleton Pattern. See https://python-patterns.guide/gang-of-four/singleton/ """ + Singleton Pattern. See https://python-patterns.guide/gang-of-four/singleton/ + """ + if cls._instance is None: cls._instance = super().__new__(cls) cls._instance.lock = threading.Lock() diff --git a/dsp/utils/utils.py b/dsp/utils/utils.py index 69e8d812a..d5a30b0e3 100644 --- a/dsp/utils/utils.py +++ b/dsp/utils/utils.py @@ -47,8 +47,10 @@ def create_directory(path): def deduplicate(seq: list[str]) -> list[str]: - """Source: https://stackoverflow.com/a/480227/1493011 """ + Source: https://stackoverflow.com/a/480227/1493011 + """ + seen = set() return [x for x in seq if not (x in seen or seen.add(x))] @@ -119,9 +121,11 @@ def flatten(L): def zipstar(L, lazy=False): - """A much faster A, B, C = zip(*[(a, b, c), (a, b, c), ...]) + """ + A much faster A, B, C = zip(*[(a, b, c), (a, b, c), ...]) May return lists or tuples. """ + if len(L) == 0: return L @@ -163,8 +167,10 @@ def groupby_first_item(lst): def process_grouped_by_first_item(lst): - """Requires items in list to already be grouped by first item. """ + Requires items in list to already be grouped by first item. + """ + groups = defaultdict(list) started = False @@ -188,10 +194,12 @@ def process_grouped_by_first_item(lst): def grouper(iterable, n, fillvalue=None): - """Collect data into fixed-length chunks or blocks - Example: grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" - Source: https://docs.python.org/3/library/itertools.html#itertools-recipes """ + Collect data into fixed-length chunks or blocks + Example: grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" + Source: https://docs.python.org/3/library/itertools.html#itertools-recipes + """ + args = [iter(iterable)] * n return itertools.zip_longest(*args, fillvalue=fillvalue) diff --git a/dspy/datasets/dataset.py b/dspy/datasets/dataset.py index 69225d3b4..c66c5edc2 100644 --- a/dspy/datasets/dataset.py +++ b/dspy/datasets/dataset.py @@ -56,9 +56,11 @@ def test(self): return self._test_ def _shuffle_and_sample(self, split, data, size, seed=0): - """The setting (seed=s, size=N) is always a subset - of the setting (seed=s, size=M) for N < M. - """ + ''' + The setting (seed=s, size=N) is always a subset + of the setting (seed=s, size=M) for N < M. + ''' + data = list(data) # Shuffle the data irrespective of the requested size. diff --git a/dspy/predict/aggregation.py b/dspy/predict/aggregation.py index 3f73ed020..4cb6df3f9 100644 --- a/dspy/predict/aggregation.py +++ b/dspy/predict/aggregation.py @@ -5,10 +5,12 @@ def majority(prediction_or_completions, normalize=default_normalize, field=None): - """Returns the most common completion for the target field (or the last field) in the signature. - When normalize returns None, that completion is ignored. - In case of a tie, earlier completion are prioritized. """ + Returns the most common completion for the target field (or the last field) in the signature. + When normalize returns None, that completion is ignored. + In case of a tie, earlier completion are prioritized. + """ + assert any(isinstance(prediction_or_completions, t) for t in [Prediction, Completions, list]) input_type = type(prediction_or_completions) diff --git a/dspy/predict/langchain.py b/dspy/predict/langchain.py index 9cc00547c..86d439f50 100644 --- a/dspy/predict/langchain.py +++ b/dspy/predict/langchain.py @@ -17,8 +17,7 @@ class Template2Signature(dspy.Signature): """You are a processor for prompts. I will give you a prompt template (Python f-string) for an arbitrary task for other LMs. - Your job is to prepare three modular pieces: (i) any essential task instructions or guidelines, (ii) a list of variable names for inputs, (iv) the variable name for output. - """ +Your job is to prepare three modular pieces: (i) any essential task instructions or guidelines, (ii) a list of variable names for inputs, (iv) the variable name for output.""" template = dspy.InputField(format=lambda x: f"```\n\n{x.strip()}\n\n```\n\nLet's now prepare three modular pieces.") essential_instructions = dspy.OutputField() diff --git a/dspy/primitives/assertions.py b/dspy/primitives/assertions.py index aba9c2492..19f1aea3a 100644 --- a/dspy/primitives/assertions.py +++ b/dspy/primitives/assertions.py @@ -326,7 +326,8 @@ def forward(self, *args, **kwargs): def assert_transform_module( module, assertion_handler=default_assertion_handler, **handler_args, ): - """Transform a module to handle assertions. + """ + Transform a module to handle assertions. """ if not getattr(module, "forward", False): raise ValueError( diff --git a/dspy/primitives/module.py b/dspy/primitives/module.py index 9c22c799c..bee80338f 100644 --- a/dspy/primitives/module.py +++ b/dspy/primitives/module.py @@ -8,8 +8,10 @@ def __init__(self): pass def named_parameters(self): - """Unlike PyTorch, handles (non-recursive) lists of parameters too. """ + Unlike PyTorch, handles (non-recursive) lists of parameters too. + """ + from dspy.predict.parameter import Parameter visited = set() diff --git a/dspy/primitives/program.py b/dspy/primitives/program.py index de286127f..aa499d908 100644 --- a/dspy/primitives/program.py +++ b/dspy/primitives/program.py @@ -55,7 +55,8 @@ def map_named_predictors(self, func): return self def activate_assertions(self, handler=backtrack_handler, **handler_args): - """Activates assertions for the module. + """ + Activates assertions for the module. The default handler is the backtrack_handler. """ assert_transform_module(self, handler, **handler_args) diff --git a/dspy/primitives/python_interpreter.py b/dspy/primitives/python_interpreter.py index 8264267f1..1b7456c7b 100644 --- a/dspy/primitives/python_interpreter.py +++ b/dspy/primitives/python_interpreter.py @@ -107,7 +107,7 @@ def __init__(self, action_space: Dict[str, Any], def execute(self, code: str, state: Optional[Dict[str, Any]] = None, fuzz_state: Optional[Dict[str, Any]] = None, keep_state: bool = True) -> Any: - r"""Execute the input python codes in a security environment. + r""" Execute the input python codes in a security environment. Args: code (str): Generated python code to be executed. @@ -585,7 +585,7 @@ def execute( represents the value of the last statement (excluding "import") in the code. This value could potentially be the desired result of the LLM-generated code. - """ + """ # NOTE: Only supports Python code for now. if not interpreter: interpreter = PythonInterpreter(action_space=globals()) diff --git a/dspy/retrieve/chromadb_rm.py b/dspy/retrieve/chromadb_rm.py index f2f5aba20..07ef407d1 100644 --- a/dspy/retrieve/chromadb_rm.py +++ b/dspy/retrieve/chromadb_rm.py @@ -1,4 +1,5 @@ -"""Retriever model for chromadb +""" +Retriever model for chromadb """ from typing import List, Optional, Union @@ -34,7 +35,8 @@ class ChromadbRM(dspy.Retrieve): - """A retrieval module that uses chromadb to return the top passages for a given query. + """ + A retrieval module that uses chromadb to return the top passages for a given query. Assumes that the chromadb index has been created and populated with the following metadata: - documents: The text of the passage @@ -92,6 +94,7 @@ def _init_chromadb( Returns: """ + self._chromadb_client = chromadb.Client( Settings( persist_directory=persist_directory, diff --git a/dspy/retrieve/clarifai_rm.py b/dspy/retrieve/clarifai_rm.py index 3fc132502..654234d2c 100644 --- a/dspy/retrieve/clarifai_rm.py +++ b/dspy/retrieve/clarifai_rm.py @@ -17,7 +17,8 @@ class ClarifaiRM(dspy.Retrieve): - """Retrieval module uses clarifai to return the Top K relevant pasages for the given query. + """ + Retrieval module uses clarifai to return the Top K relevant pasages for the given query. Assuming that you have ingested the source documents into clarifai App, where it is indexed and stored. Args: @@ -59,7 +60,6 @@ def forward( self, query_or_queries: Union[str, List[str]], k: Optional[int] = None, ) -> dspy.Prediction: """Uses clarifai-python SDK search function and retrieves top_k similar passages for given query, - Args: query_or_queries : single query or list of queries k : Top K relevant documents to return diff --git a/dspy/retrieve/databricks_rm.py b/dspy/retrieve/databricks_rm.py index 5fea160c7..c275bdddc 100644 --- a/dspy/retrieve/databricks_rm.py +++ b/dspy/retrieve/databricks_rm.py @@ -9,7 +9,8 @@ class DatabricksRM(dspy.Retrieve): - """A retrieval module that uses Databricks Vector Search Endpoint to return the top-k embeddings for a given query. + """ + A retrieval module that uses Databricks Vector Search Endpoint to return the top-k embeddings for a given query. Args: databricks_index_name (str): Databricks vector search index to query diff --git a/dspy/retrieve/deeplake_rm.py b/dspy/retrieve/deeplake_rm.py index 176cda1fc..235108a91 100644 --- a/dspy/retrieve/deeplake_rm.py +++ b/dspy/retrieve/deeplake_rm.py @@ -1,4 +1,5 @@ -"""Retriever model for deeplake +""" +Retriever model for deeplake """ from collections import defaultdict @@ -22,7 +23,9 @@ class DeeplakeRM(dspy.Retrieve): - """A retriever module that uses deeplake to return the top passages for a given query. + + """ + A retriever module that uses deeplake to return the top passages for a given query. Assumes that a Deep Lake Vector Store has been created and populated with the following payload: - text: The text of the passage @@ -78,6 +81,7 @@ def embedding_function(self, texts, model="text-embedding-ada-002"): def forward( self, query_or_queries: Union[str, List[str]], k: Optional[int], ) -> dspy.Prediction: + """Search with DeepLake for self.k top passages for query Args: diff --git a/dspy/retrieve/marqo_rm.py b/dspy/retrieve/marqo_rm.py index 5ec932e6c..29c52fdb4 100644 --- a/dspy/retrieve/marqo_rm.py +++ b/dspy/retrieve/marqo_rm.py @@ -12,7 +12,8 @@ ) class MarqoRM(dspy.Retrieve): - """A retrieval module that uses Marqo to return the top passages for a given query. + """ + A retrieval module that uses Marqo to return the top passages for a given query. Assumes that a Marqo index has been created and populated with the following payload: - document: The text of the passage diff --git a/dspy/retrieve/pgvector_rm.py b/dspy/retrieve/pgvector_rm.py index 295461b5a..cf1773f17 100644 --- a/dspy/retrieve/pgvector_rm.py +++ b/dspy/retrieve/pgvector_rm.py @@ -15,7 +15,8 @@ class PgVectorRM(dspy.Retrieve): - """Implements a retriever that (as the name suggests) uses pgvector to retrieve passages, + """ + Implements a retriever that (as the name suggests) uses pgvector to retrieve passages, using a raw SQL query and a postgresql connection managed by psycopg2. It needs to register the pgvector extension with the psycopg2 connection @@ -64,7 +65,8 @@ def __init__( embedding_field: str = "embedding", fields: List[str] = ['text'], ): - """K = 20 is the number of paragraphs to retrieve + """ + k = 20 is the number of paragraphs to retrieve """ self.openai_client = openai_client diff --git a/dspy/retrieve/pinecone_rm.py b/dspy/retrieve/pinecone_rm.py index 70589a0f6..0328bc6ba 100644 --- a/dspy/retrieve/pinecone_rm.py +++ b/dspy/retrieve/pinecone_rm.py @@ -1,4 +1,5 @@ -"""Retriever model for Pinecone +""" +Retriever model for Pinecone Author: Dhar Rawal (@drawal1) """ @@ -33,7 +34,8 @@ ERRORS = (openai.RateLimitError, openai.APIError) class PineconeRM(dspy.Retrieve): - """A retrieval module that uses Pinecone to return the top passages for a given query. + """ + A retrieval module that uses Pinecone to return the top passages for a given query. Assumes that the Pinecone index has been created and populated with the following metadata: - text: The text of the passage @@ -133,6 +135,7 @@ def _init_pinecone( Returns: pinecone.Index: The loaded index. """ + # Pinecone init overrides default if kwargs are present, so we need to exclude if None kwargs = {} if api_key: diff --git a/dspy/retrieve/qdrant_rm.py b/dspy/retrieve/qdrant_rm.py index 7ddaa47b7..5c2af050b 100644 --- a/dspy/retrieve/qdrant_rm.py +++ b/dspy/retrieve/qdrant_rm.py @@ -14,7 +14,8 @@ class QdrantRM(dspy.Retrieve): - """A retrieval module that uses Qdrant to return the top passages for a given query. + """ + A retrieval module that uses Qdrant to return the top passages for a given query. Assumes that a Qdrant collection has been created and populated with the following payload: - document: The text of the passage @@ -58,7 +59,6 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> Args: query_or_queries (Union[str, List[str]]): The query or queries to search for. k (Optional[int]): The number of top passages to retrieve. Defaults to self.k. - Returns: dspy.Prediction: An object containing the retrieved passages. """ diff --git a/dspy/retrieve/vectara_rm.py b/dspy/retrieve/vectara_rm.py index 889993520..047c70d6c 100644 --- a/dspy/retrieve/vectara_rm.py +++ b/dspy/retrieve/vectara_rm.py @@ -15,7 +15,8 @@ def remove_snippet(s: str) -> str: return s.replace(START_SNIPPET, "").replace(END_SNIPPET, "") class VectaraRM(dspy.Retrieve): - """A retrieval module that uses Vectara to return the top passages for a given query. + """ + A retrieval module that uses Vectara to return the top passages for a given query. Assumes that a Vectara corpus has been created and populated with the following payload: - document: The text of the passage @@ -69,7 +70,6 @@ def _vectara_query( limit: int = 3, ) -> List[str]: """Query Vectara index to get for top k matching passages. - Args: query: query string """ @@ -135,7 +135,6 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> Args: query_or_queries (Union[str, List[str]]): The query or queries to search for. k (Optional[int]): The number of top passages to retrieve. Defaults to self.k. - Returns: dspy.Prediction: An object containing the retrieved passages. """ diff --git a/dspy/retrieve/weaviate_rm.py b/dspy/retrieve/weaviate_rm.py index 4951032aa..61e8d1ef0 100644 --- a/dspy/retrieve/weaviate_rm.py +++ b/dspy/retrieve/weaviate_rm.py @@ -12,7 +12,8 @@ class WeaviateRM(dspy.Retrieve): - """A retrieval module that uses Weaviate to return the top passages for a given query. + """ + A retrieval module that uses Weaviate to return the top passages for a given query. Assumes that a Weaviate collection has been created and populated with the following payload: - content: The text of the passage @@ -58,10 +59,10 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int]) -> Args: query_or_queries (Union[str, List[str]]): The query or queries to search for. k (Optional[int]): The number of top passages to retrieve. Defaults to self.k. - Returns: dspy.Prediction: An object containing the retrieved passages. """ + k = k if k is not None else self.k queries = ( [query_or_queries] diff --git a/dspy/retrieve/weaviate_rm_test.py b/dspy/retrieve/weaviate_rm_test.py index d638639b2..fa2c97237 100644 --- a/dspy/retrieve/weaviate_rm_test.py +++ b/dspy/retrieve/weaviate_rm_test.py @@ -7,7 +7,8 @@ # Connect DSPy # Test this API -"""from dspy.retrieve.weaviate_rm import WeaviateRM +""" +from dspy.retrieve.weaviate_rm import WeaviateRM retriever_model = WeaviateRM("WeaviateBlogChunk", weaviate_client=weaviate_client) dspy.settings.configure(rm=retriever_model) diff --git a/dspy/retrieve/you_rm.py b/dspy/retrieve/you_rm.py index 8534a3645..25a62ccea 100644 --- a/dspy/retrieve/you_rm.py +++ b/dspy/retrieve/you_rm.py @@ -27,6 +27,7 @@ def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int] = No Returns: dspy.Prediction: An object containing the retrieved passages. """ + k = k if k is not None else self.k queries = ( diff --git a/dspy/teleprompt/ensemble.py b/dspy/teleprompt/ensemble.py index 7ed13deb4..5e0db9bca 100644 --- a/dspy/teleprompt/ensemble.py +++ b/dspy/teleprompt/ensemble.py @@ -9,6 +9,7 @@ class Ensemble(Teleprompter): def __init__(self, *, reduce_fn=None, size=None, deterministic=False): """A common reduce_fn is dspy.majority.""" + assert deterministic is False, "TODO: Implement example hashing for deterministic ensemble." self.reduce_fn = reduce_fn diff --git a/dspy/teleprompt/signature_opt.py b/dspy/teleprompt/signature_opt.py index 47789ae9f..d71aa69a7 100644 --- a/dspy/teleprompt/signature_opt.py +++ b/dspy/teleprompt/signature_opt.py @@ -41,8 +41,7 @@ class BasicGenerateInstruction(Signature): class GenerateInstructionGivenAttempts(dspy.Signature): """You are an instruction optimizer for large language models. I will give some task instructions I've tried, along with their corresponding validation scores. The instructions are arranged in increasing order based on their scores, where higher scores indicate better quality. - Your task is to propose a new instruction that will lead a good language model to perform the task even better. Don't be afraid to be creative. - """ +Your task is to propose a new instruction that will lead a good language model to perform the task even better. Don't be afraid to be creative.""" attempted_instructions = dspy.InputField(format=dsp.passages2text) proposed_instruction = dspy.OutputField(desc="The improved instructions for the language model") @@ -102,7 +101,7 @@ def _print_signature(self, predictor): def compile(self, student, *, devset, eval_kwargs): - """Student is a program that needs to be optimized, note that it may be zero-shot or already pre-optimized for demos != []""" + """student is a program that needs to be optimized, note that it may be zero-shot or already pre-optimized for demos != []""" module = student.deepcopy() evaluate = Evaluate(devset=devset, metric=self.metric, **eval_kwargs) total_calls = 0 diff --git a/dspy/teleprompt/signature_opt_bayesian.py b/dspy/teleprompt/signature_opt_bayesian.py index 87fc9ad4e..e316462c9 100644 --- a/dspy/teleprompt/signature_opt_bayesian.py +++ b/dspy/teleprompt/signature_opt_bayesian.py @@ -58,8 +58,7 @@ class BasicGenerateInstructionWithDataObservations(Signature): class BasicGenerateInstructionWithExamples(dspy.Signature): ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``examples`` of the expected inputs and outputs. - Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative. - """) +Your task is to propose an instruction that will lead a good language model to perform the task well. Don't be afraid to be creative.""") # attempted_instructions = dspy.InputField(format=str, desc="Previously attempted task instructions, along with their resulting validation score, and an example of the instruction in use on a sample from our dataset.") basic_instruction = dspy.InputField(desc="The initial instructions before optimization") # examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") @@ -70,8 +69,7 @@ class BasicGenerateInstructionWithExamples(dspy.Signature): class BasicGenerateInstructionWithExamplesAndDataObservations(dspy.Signature): ("""You are an instruction optimizer for large language models. I will give you a ``signature`` of fields (inputs and outputs) in English. Specifically, I will also provide you with the current ``basic instruction`` that is being used for this task. I will also provide you with some ``observations`` I have made about the dataset and task, along with some ``examples`` of the expected inputs and outputs. - Your task is to propose a new improved instruction and prefix for the output field that will lead a good language model to perform the task well. Don't be afraid to be creative. - """) +Your task is to propose a new improved instruction and prefix for the output field that will lead a good language model to perform the task well. Don't be afraid to be creative.""") basic_instruction = dspy.InputField(desc="The initial instructions before optimization") observations = dspy.InputField(desc="Observations about the dataset and task") examples = dspy.InputField(format=dsp.passages2text, desc="Example(s) of the task") diff --git a/testing/tasks/biodex.py b/testing/tasks/biodex.py index 79d4bb84d..6e51745b3 100644 --- a/testing/tasks/biodex.py +++ b/testing/tasks/biodex.py @@ -365,8 +365,10 @@ def base_ground(reaction, K): @lru_cache(maxsize=100000) def ground_v1(reaction, K=3): - """Prefers exact matches over fuzzy matches, when available. """ + Prefers exact matches over fuzzy matches, when available. + """ + exact_matches, fuzzy_matches = base_ground(reaction, K) matches = exact_matches[:1] or fuzzy_matches @@ -377,8 +379,10 @@ def ground_v1(reaction, K=3): @lru_cache(maxsize=100000) def ground_v2(reaction, K=1): - """When K=1 (default), returns exact matches (if available) or the best fuzzy match. """ + When K=1 (default), returns exact matches (if available) or the best fuzzy match. + """ + exact_matches, fuzzy_matches = base_ground(reaction, K) matches = [(match.score / 100.0, match.node.term) for match in (exact_matches[:1] + fuzzy_matches)] @@ -391,7 +395,8 @@ def ground_v2(reaction, K=1): @lru_cache(maxsize=100000) def ground_v4(reaction, K=3): - """Returns the best three matches (including one exact match, if available) and applies a prior. + """ + Returns the best three matches (including one exact match, if available) and applies a prior. """ exact_matches, fuzzy_matches = base_ground(reaction, K) @@ -403,8 +408,10 @@ def ground_v4(reaction, K=3): @lru_cache(maxsize=100000) def ground_v4b(reaction, K=3): - """Returns the best three matches (including one exact match, if available) and applies a prior. """ + Returns the best three matches (including one exact match, if available) and applies a prior. + """ + exact_matches, fuzzy_matches = base_ground(reaction, K) matches = [((match.score / 100.0) * math.log(match.node.count + 0.1), match.node.term) @@ -415,8 +422,10 @@ def ground_v4b(reaction, K=3): @lru_cache(maxsize=100000) def ground_v4c(reaction, K=3): - """Returns the best three matches (including one exact match, if available) and applies a prior. """ + Returns the best three matches (including one exact match, if available) and applies a prior. + """ + exact_matches, fuzzy_matches = base_ground(reaction, K) matches = [((match.score / 100.0) * (match.node.count + 0.1), match.node.term) From 472b166420fccc8adff053a33c7deaf75ae5cae8 Mon Sep 17 00:00:00 2001 From: Connor Shorten Date: Sat, 9 Mar 2024 13:10:08 -0500 Subject: [PATCH 63/79] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2516f5d98..713466775 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ ] [project.optional-dependencies] -anthropic = ["anthropic~=0.18.0"], +anthropic = ["anthropic~=0.18.0"] chromadb = ["chromadb~=0.4.14"] qdrant = ["qdrant-client~=1.6.2", "fastembed~=0.1.0"] marqo = ["marqo"] From 226a0d94672f03a5d33215c5efce473a1a3419be Mon Sep 17 00:00:00 2001 From: arnavsinghvi11 <54859892+arnavsinghvi11@users.noreply.github.com> Date: Sat, 9 Mar 2024 11:47:35 -0800 Subject: [PATCH 64/79] Update databricks_rm.py -added support for doc_ids --- dspy/retrieve/databricks_rm.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/dspy/retrieve/databricks_rm.py b/dspy/retrieve/databricks_rm.py index c275bdddc..721a3553f 100644 --- a/dspy/retrieve/databricks_rm.py +++ b/dspy/retrieve/databricks_rm.py @@ -1,7 +1,7 @@ import os from collections import defaultdict -from typing import List, Union - +from typing import List, Union, Optional +import json import requests import dspy @@ -19,6 +19,8 @@ class DatabricksRM(dspy.Retrieve): columns (list[str]): Column names to include in response filters_json (str, optional): JSON string for query filters k (int, optional): Number of top embeddings to retrieve. Defaults to 3. + docs_id_column_name (str, optional): Column name for retrieved doc_ids to return. + text_column_name (str, optional): Column name for retrieved text to return. Examples: Below is a code snippet that shows how to configure Databricks Vector Search endpoints: @@ -39,7 +41,7 @@ class DatabricksRM(dspy.Retrieve): ) #Creating Vector Search Index using Python SDK - #Example for Direct Vector Acces Index + #Example for Direct Vector Access Index index = client.create_direct_access_index( endpoint_name="your_databricks_host_url", @@ -65,7 +67,7 @@ class DatabricksRM(dspy.Retrieve): self.retrieve = DatabricksRM(query=[1, 2, 3], query_type = 'vector') ``` """ - def __init__(self, databricks_index_name = None, databricks_endpoint = None, databricks_token = None, columns = None, filters_json = None, k = 3): + def __init__(self, databricks_index_name = None, databricks_endpoint = None, databricks_token = None, columns = None, filters_json = None, k = 3, docs_id_column_name = 'id', text_column_name = 'text'): super().__init__(k=k) if not databricks_token and not os.environ.get("DATABRICKS_TOKEN"): raise ValueError("You must supply databricks_token or set environment variable DATABRICKS_TOKEN") @@ -81,6 +83,8 @@ def __init__(self, databricks_index_name = None, databricks_endpoint = None, dat self.columns = columns self.filters_json = filters_json self.k = k + self.docs_id_column_name = docs_id_column_name + self.text_column_name = text_column_name def forward(self, query: Union[str, List[float]], query_type: str = 'vector') -> dspy.Prediction: """Search with Databricks Vector Search Client for self.k top results for query @@ -120,14 +124,20 @@ def forward(self, query: Union[str, List[float]], query_type: str = 'vector') -> results = response.json() docs = defaultdict(float) + doc_ids = [] text, score = None, None for data_row in results["result"]["data_array"]: for col, val in zip(results["manifest"]["columns"], data_row): - if col["name"] == 'text': + if col["name"] == self.docs_id_column_name: + if self.docs_id_column_name == 'metadata': + docs_dict = json.loads(val) + doc_ids.append(str(docs_dict["document_id"])) + else: + doc_ids.append(str(val)) text = val if col["name"] == 'score': score = val docs[text] += score sorted_docs = sorted(docs.items(), key=lambda x: x[1], reverse=True)[:self.k] - return Prediction(docs=[doc for doc, _ in sorted_docs]) + return Prediction(docs=[doc for doc, _ in sorted_docs], doc_ids = doc_ids) From e7549fbf4daac1b352b112f26c77237bb9ad361d Mon Sep 17 00:00:00 2001 From: Arnav Singhvi Date: Sat, 9 Mar 2024 11:50:25 -0800 Subject: [PATCH 65/79] Update databricks_rm.py --- dspy/retrieve/databricks_rm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dspy/retrieve/databricks_rm.py b/dspy/retrieve/databricks_rm.py index 721a3553f..ecddddb85 100644 --- a/dspy/retrieve/databricks_rm.py +++ b/dspy/retrieve/databricks_rm.py @@ -1,7 +1,8 @@ +import json import os from collections import defaultdict -from typing import List, Union, Optional -import json +from typing import List, Union + import requests import dspy From 61ac2f7950b08f97dee215e112e1bd840759b3ee Mon Sep 17 00:00:00 2001 From: Isaac Miller Date: Sat, 9 Mar 2024 14:12:56 -0600 Subject: [PATCH 66/79] Add ruff rule back --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 713466775..0637ba7fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,6 +173,7 @@ exclude_lines = [ line-length = 120 indent-width = 4 target-version = "py39" +extend-unsafe-fixes = ["D"] [tool.ruff.lint] # List of rules: https://docs.astral.sh/ruff/rules From b8fe312863849140d4aad2b497d99a9adc321efc Mon Sep 17 00:00:00 2001 From: Isaac Miller Date: Sat, 9 Mar 2024 13:51:27 -0600 Subject: [PATCH 67/79] Make anthropic import optional for tests --- dsp/modules/anthropic.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dsp/modules/anthropic.py b/dsp/modules/anthropic.py index 99c9f225a..859e43665 100644 --- a/dsp/modules/anthropic.py +++ b/dsp/modules/anthropic.py @@ -2,11 +2,16 @@ import backoff import json from typing import Optional, Any -from anthropic import Anthropic, RateLimitError from dsp.modules.lm import LM import logging +try: + import anthropic + anthropic_rate_limit = anthropic.RateLimitError +except ImportError: + anthropic_rate_limit = Exception + logger = logging.getLogger(__name__) @@ -39,6 +44,12 @@ def __init__( **kwargs ): super().__init__(model) + + try: + from anthropic import Anthropic, RateLimitError + except ImportError as err: + raise ImportError("Claude requires `pip install anthropic`.") from err + self.provider = "anthropic" self.api_key = api_key = os.environ.get("ANTHROPIC_API_KEY") if api_key is None else api_key self.api_base = BASE_URL if api_base is None else api_base @@ -84,7 +95,7 @@ def basic_request(self, prompt: str, **kwargs): @backoff.on_exception( backoff.expo, - (RateLimitError), + (anthropic_rate_limit), max_time=1000, max_tries=8, on_backoff=backoff_hdlr, From 89036644d4570ca033590796b8c094febd993fe6 Mon Sep 17 00:00:00 2001 From: Isaac Miller Date: Sat, 9 Mar 2024 14:14:12 -0600 Subject: [PATCH 68/79] Apply ruff fix --- dsp/modules/__init__.py | 2 +- dsp/modules/anthropic.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dsp/modules/__init__.py b/dsp/modules/__init__.py index 06e1d6f07..fdf59eabc 100644 --- a/dsp/modules/__init__.py +++ b/dsp/modules/__init__.py @@ -1,3 +1,4 @@ +from .anthropic import Claude from .azure_openai import AzureOpenAI from .bedrock import * from .cache_utils import * @@ -13,4 +14,3 @@ from .pyserini import * from .sbert import * from .sentence_vectorizer import * -from .anthropic import Claude diff --git a/dsp/modules/anthropic.py b/dsp/modules/anthropic.py index 859e43665..68f30ce7a 100644 --- a/dsp/modules/anthropic.py +++ b/dsp/modules/anthropic.py @@ -1,10 +1,10 @@ +import logging import os +from typing import Any, Optional + import backoff -import json -from typing import Optional, Any from dsp.modules.lm import LM -import logging try: import anthropic @@ -41,7 +41,7 @@ def __init__( model: str = "claude-instant-1.2", api_key: Optional[str] = None, api_base: Optional[str] = None, - **kwargs + **kwargs, ): super().__init__(model) From e7443d65f634dbd834e4f38e9980a7967237c0ac Mon Sep 17 00:00:00 2001 From: Isaac Miller Date: Sat, 9 Mar 2024 14:15:24 -0600 Subject: [PATCH 69/79] Update poetry.lock --- poetry.lock | 572 ++++++++++++++++++++++++++++------------------------ 1 file changed, 304 insertions(+), 268 deletions(-) diff --git a/poetry.lock b/poetry.lock index 30ec76981..670e11592 100644 --- a/poetry.lock +++ b/poetry.lock @@ -151,6 +151,30 @@ files = [ {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] +[[package]] +name = "anthropic" +version = "0.18.1" +description = "The official Python library for the anthropic API" +optional = true +python-versions = ">=3.7" +files = [ + {file = "anthropic-0.18.1-py3-none-any.whl", hash = "sha256:b85aee64f619ce1b1964ba733a09adc4053e7bc4e6d4186001229ec191099dcf"}, + {file = "anthropic-0.18.1.tar.gz", hash = "sha256:f5d1caafd43f6cc933a79753a93531605095f040a384f6a900c3de9c3fb6694e"}, +] + +[package.dependencies] +anyio = ">=3.5.0,<5" +distro = ">=1.7.0,<2" +httpx = ">=0.23.0,<1" +pydantic = ">=1.9.0,<3" +sniffio = "*" +tokenizers = ">=0.13.0" +typing-extensions = ">=4.7,<5" + +[package.extras] +bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] +vertex = ["google-auth (>=2,<3)"] + [[package]] name = "anyio" version = "4.3.0" @@ -366,13 +390,13 @@ lxml = ["lxml"] [[package]] name = "cachetools" -version = "5.3.2" +version = "5.3.3" description = "Extensible memoizing collections and decorators" optional = true python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, - {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, + {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, + {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, ] [[package]] @@ -755,20 +779,20 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "datasets" -version = "2.17.1" +version = "2.18.0" description = "HuggingFace community-driven open-source library of datasets" optional = false python-versions = ">=3.8.0" files = [ - {file = "datasets-2.17.1-py3-none-any.whl", hash = "sha256:346974daf2fe9c14ddb35646896b2308b95e7dc27709d1a6e25273573b140cf8"}, - {file = "datasets-2.17.1.tar.gz", hash = "sha256:66ec24077807f374f379b62ab0256c4dcb7c38a57ff1529a22993e8d95f2f9f1"}, + {file = "datasets-2.18.0-py3-none-any.whl", hash = "sha256:f1bbf0e2896917a914de01cbd37075b14deea3837af87ad0d9f697388ccaeb50"}, + {file = "datasets-2.18.0.tar.gz", hash = "sha256:cdf8b8c6abf7316377ba4f49f9589a4c74556d6b481afd0abd2284f3d69185cb"}, ] [package.dependencies] aiohttp = "*" dill = ">=0.3.0,<0.3.9" filelock = "*" -fsspec = {version = ">=2023.1.0,<=2023.10.0", extras = ["http"]} +fsspec = {version = ">=2023.1.0,<=2024.2.0", extras = ["http"]} huggingface-hub = ">=0.19.4" multiprocess = "*" numpy = ">=1.17" @@ -785,11 +809,11 @@ xxhash = "*" apache-beam = ["apache-beam (>=2.26.0)"] audio = ["librosa", "soundfile (>=0.12.1)"] benchmarks = ["tensorflow (==2.12.0)", "torch (==2.0.1)", "transformers (==4.30.1)"] -dev = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "jax (>=0.3.14)", "jaxlib (>=0.3.14)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "ruff (>=0.1.5)", "s3fs", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "torch (>=2.0.0)", "transformers", "typing-extensions (>=4.6.1)", "zstandard"] +dev = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "jax (>=0.3.14)", "jaxlib (>=0.3.14)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "ruff (>=0.3.0)", "s3fs", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "torch (>=2.0.0)", "transformers", "typing-extensions (>=4.6.1)", "zstandard"] docs = ["s3fs", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos", "torch", "transformers"] jax = ["jax (>=0.3.14)", "jaxlib (>=0.3.14)"] metrics-tests = ["Werkzeug (>=1.0.1)", "accelerate", "bert-score (>=0.3.6)", "jiwer", "langdetect", "mauve-text", "nltk", "requests-file (>=1.5.1)", "rouge-score", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "six (>=1.15.0,<1.16.0)", "spacy (>=3.0.0)", "texttable (>=1.6.3)", "tldextract", "tldextract (>=3.1.0)", "toml (>=0.10.1)", "typer (<0.5.0)"] -quality = ["ruff (>=0.1.5)"] +quality = ["ruff (>=0.3.0)"] s3 = ["s3fs"] tensorflow = ["tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos"] tensorflow-gpu = ["tensorflow-gpu (>=2.2.0,!=2.6.0,!=2.6.1)"] @@ -871,6 +895,17 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] +[[package]] +name = "distro" +version = "1.9.0" +description = "Distro - an OS platform information API" +optional = true +python-versions = ">=3.6" +files = [ + {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, + {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, +] + [[package]] name = "dnspython" version = "2.6.1" @@ -999,13 +1034,13 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "flatbuffers" -version = "23.5.26" +version = "24.3.7" description = "The FlatBuffers serialization format for Python" optional = true 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"}, + {file = "flatbuffers-24.3.7-py2.py3-none-any.whl", hash = "sha256:80c4f5dcad0ee76b7e349671a0d657f2fbba927a0244f88dd3f5ed6a3694e1fc"}, + {file = "flatbuffers-24.3.7.tar.gz", hash = "sha256:0895c22b9a6019ff2f4de2e5e2f7cd15914043e6e7033a94c0c6369422690f22"}, ] [[package]] @@ -1096,18 +1131,17 @@ files = [ [[package]] name = "fsspec" -version = "2023.10.0" +version = "2024.2.0" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - {file = "fsspec-2023.10.0-py3-none-any.whl", hash = "sha256:346a8f024efeb749d2a5fca7ba8854474b1ff9af7c3faaf636a4548781136529"}, - {file = "fsspec-2023.10.0.tar.gz", hash = "sha256:330c66757591df346ad3091a53bd907e15348c2ba17d63fd54f5c39c4457d2a5"}, + {file = "fsspec-2024.2.0-py3-none-any.whl", hash = "sha256:817f969556fa5916bc682e02ca2045f96ff7f586d45110fcb76022063ad2c7d8"}, + {file = "fsspec-2024.2.0.tar.gz", hash = "sha256:b6ad1a679f760dda52b1168c859d01b7b80648ea6f7f7c7f5a8a91dc3f3ecb84"}, ] [package.dependencies] aiohttp = {version = "<4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1", optional = true, markers = "extra == \"http\""} -requests = {version = "*", optional = true, markers = "extra == \"http\""} [package.extras] abfs = ["adlfs"] @@ -1124,7 +1158,7 @@ github = ["requests"] gs = ["gcsfs"] gui = ["panel"] hdfs = ["pyarrow (>=1)"] -http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] libarchive = ["libarchive-c"] oci = ["ocifs"] s3 = ["s3fs"] @@ -1169,13 +1203,13 @@ dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "google-auth" -version = "2.28.1" +version = "2.28.2" description = "Google Authentication Library" optional = true python-versions = ">=3.7" files = [ - {file = "google-auth-2.28.1.tar.gz", hash = "sha256:34fc3046c257cedcf1622fc4b31fc2be7923d9b4d44973d481125ecc50d83885"}, - {file = "google_auth-2.28.1-py2.py3-none-any.whl", hash = "sha256:25141e2d7a14bfcba945f5e9827f98092716e99482562f15306e5b026e21aa72"}, + {file = "google-auth-2.28.2.tar.gz", hash = "sha256:80b8b4969aa9ed5938c7828308f20f035bc79f9d8fb8120bf9dc8db20b41ba30"}, + {file = "google_auth-2.28.2-py2.py3-none-any.whl", hash = "sha256:9fd67bbcd40f16d9d42f950228e9cf02a2ded4ae49198b27432d0cded5a74c38"}, ] [package.dependencies] @@ -1280,13 +1314,13 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.41.0" +version = "0.41.3" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." optional = false python-versions = ">=3.8" files = [ - {file = "griffe-0.41.0-py3-none-any.whl", hash = "sha256:8aa7fc6eb00cb80af9c0198178c6b7110cb59fa2c5187bb13ea25eebbe4dd928"}, - {file = "griffe-0.41.0.tar.gz", hash = "sha256:850128c3198c18713eaf0a6cc8572e590a16b1965f72a4e871e66cf84740903f"}, + {file = "griffe-0.41.3-py3-none-any.whl", hash = "sha256:27b4610f1ba6e5d039e9f0a2c97232e13463df75e53cb1833e0679f3377b9de2"}, + {file = "griffe-0.41.3.tar.gz", hash = "sha256:9edcfa9f57f4d9c5fcc6d5ce067c67a685b7101a21a7d11848ce0437368e474c"}, ] [package.dependencies] @@ -1294,135 +1328,135 @@ colorama = ">=0.4" [[package]] name = "grpcio" -version = "1.62.0" +version = "1.62.1" description = "HTTP/2-based RPC framework" optional = true python-versions = ">=3.7" files = [ - {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, - {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, - {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, - {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, - {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, - {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, - {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, - {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, - {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, - {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, - {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, - {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, - {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, - {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, - {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, - {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, - {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, - {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, - {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, - {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, - {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, - {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, - {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, - {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, + {file = "grpcio-1.62.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:179bee6f5ed7b5f618844f760b6acf7e910988de77a4f75b95bbfaa8106f3c1e"}, + {file = "grpcio-1.62.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:48611e4fa010e823ba2de8fd3f77c1322dd60cb0d180dc6630a7e157b205f7ea"}, + {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:b2a0e71b0a2158aa4bce48be9f8f9eb45cbd17c78c7443616d00abbe2a509f6d"}, + {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbe80577c7880911d3ad65e5ecc997416c98f354efeba2f8d0f9112a67ed65a5"}, + {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f6c693d446964e3292425e1d16e21a97a48ba9172f2d0df9d7b640acb99243"}, + {file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:77c339403db5a20ef4fed02e4d1a9a3d9866bf9c0afc77a42234677313ea22f3"}, + {file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b5a4ea906db7dec694098435d84bf2854fe158eb3cd51e1107e571246d4d1d70"}, + {file = "grpcio-1.62.1-cp310-cp310-win32.whl", hash = "sha256:4187201a53f8561c015bc745b81a1b2d278967b8de35f3399b84b0695e281d5f"}, + {file = "grpcio-1.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:844d1f3fb11bd1ed362d3fdc495d0770cfab75761836193af166fee113421d66"}, + {file = "grpcio-1.62.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:833379943d1728a005e44103f17ecd73d058d37d95783eb8f0b28ddc1f54d7b2"}, + {file = "grpcio-1.62.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:c7fcc6a32e7b7b58f5a7d27530669337a5d587d4066060bcb9dee7a8c833dfb7"}, + {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:fa7d28eb4d50b7cbe75bb8b45ed0da9a1dc5b219a0af59449676a29c2eed9698"}, + {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48f7135c3de2f298b833be8b4ae20cafe37091634e91f61f5a7eb3d61ec6f660"}, + {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f11fd63365ade276c9d4a7b7df5c136f9030e3457107e1791b3737a9b9ed6a"}, + {file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b49fd8fe9f9ac23b78437da94c54aa7e9996fbb220bac024a67469ce5d0825f"}, + {file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:482ae2ae78679ba9ed5752099b32e5fe580443b4f798e1b71df412abf43375db"}, + {file = "grpcio-1.62.1-cp311-cp311-win32.whl", hash = "sha256:1faa02530b6c7426404372515fe5ddf66e199c2ee613f88f025c6f3bd816450c"}, + {file = "grpcio-1.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bd90b8c395f39bc82a5fb32a0173e220e3f401ff697840f4003e15b96d1befc"}, + {file = "grpcio-1.62.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b134d5d71b4e0837fff574c00e49176051a1c532d26c052a1e43231f252d813b"}, + {file = "grpcio-1.62.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d1f6c96573dc09d50dbcbd91dbf71d5cf97640c9427c32584010fbbd4c0e0037"}, + {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:359f821d4578f80f41909b9ee9b76fb249a21035a061a327f91c953493782c31"}, + {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a485f0c2010c696be269184bdb5ae72781344cb4e60db976c59d84dd6354fac9"}, + {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b50b09b4dc01767163d67e1532f948264167cd27f49e9377e3556c3cba1268e1"}, + {file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3227c667dccbe38f2c4d943238b887bac588d97c104815aecc62d2fd976e014b"}, + {file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3952b581eb121324853ce2b191dae08badb75cd493cb4e0243368aa9e61cfd41"}, + {file = "grpcio-1.62.1-cp312-cp312-win32.whl", hash = "sha256:83a17b303425104d6329c10eb34bba186ffa67161e63fa6cdae7776ff76df73f"}, + {file = "grpcio-1.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:6696ffe440333a19d8d128e88d440f91fb92c75a80ce4b44d55800e656a3ef1d"}, + {file = "grpcio-1.62.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:e3393b0823f938253370ebef033c9fd23d27f3eae8eb9a8f6264900c7ea3fb5a"}, + {file = "grpcio-1.62.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:83e7ccb85a74beaeae2634f10eb858a0ed1a63081172649ff4261f929bacfd22"}, + {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:882020c87999d54667a284c7ddf065b359bd00251fcd70279ac486776dbf84ec"}, + {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a10383035e864f386fe096fed5c47d27a2bf7173c56a6e26cffaaa5a361addb1"}, + {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:960edebedc6b9ada1ef58e1c71156f28689978188cd8cff3b646b57288a927d9"}, + {file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:23e2e04b83f347d0aadde0c9b616f4726c3d76db04b438fd3904b289a725267f"}, + {file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978121758711916d34fe57c1f75b79cdfc73952f1481bb9583399331682d36f7"}, + {file = "grpcio-1.62.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9084086190cc6d628f282e5615f987288b95457292e969b9205e45b442276407"}, + {file = "grpcio-1.62.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:22bccdd7b23c420a27fd28540fb5dcbc97dc6be105f7698cb0e7d7a420d0e362"}, + {file = "grpcio-1.62.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:8999bf1b57172dbc7c3e4bb3c732658e918f5c333b2942243f10d0d653953ba9"}, + {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:d9e52558b8b8c2f4ac05ac86344a7417ccdd2b460a59616de49eb6933b07a0bd"}, + {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1714e7bc935780bc3de1b3fcbc7674209adf5208ff825799d579ffd6cd0bd505"}, + {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8842ccbd8c0e253c1f189088228f9b433f7a93b7196b9e5b6f87dba393f5d5d"}, + {file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f1e7b36bdff50103af95a80923bf1853f6823dd62f2d2a2524b66ed74103e49"}, + {file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bba97b8e8883a8038606480d6b6772289f4c907f6ba780fa1f7b7da7dfd76f06"}, + {file = "grpcio-1.62.1-cp38-cp38-win32.whl", hash = "sha256:a7f615270fe534548112a74e790cd9d4f5509d744dd718cd442bf016626c22e4"}, + {file = "grpcio-1.62.1-cp38-cp38-win_amd64.whl", hash = "sha256:e6c8c8693df718c5ecbc7babb12c69a4e3677fd11de8886f05ab22d4e6b1c43b"}, + {file = "grpcio-1.62.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:73db2dc1b201d20ab7083e7041946910bb991e7e9761a0394bbc3c2632326483"}, + {file = "grpcio-1.62.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:407b26b7f7bbd4f4751dbc9767a1f0716f9fe72d3d7e96bb3ccfc4aace07c8de"}, + {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f8de7c8cef9261a2d0a62edf2ccea3d741a523c6b8a6477a340a1f2e417658de"}, + {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd5c8a1af40ec305d001c60236308a67e25419003e9bb3ebfab5695a8d0b369"}, + {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0477cb31da67846a33b1a75c611f88bfbcd427fe17701b6317aefceee1b96f"}, + {file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:60dcd824df166ba266ee0cfaf35a31406cd16ef602b49f5d4dfb21f014b0dedd"}, + {file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:973c49086cabab773525f6077f95e5a993bfc03ba8fc32e32f2c279497780585"}, + {file = "grpcio-1.62.1-cp39-cp39-win32.whl", hash = "sha256:12859468e8918d3bd243d213cd6fd6ab07208195dc140763c00dfe901ce1e1b4"}, + {file = "grpcio-1.62.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7209117bbeebdfa5d898205cc55153a51285757902dd73c47de498ad4d11332"}, + {file = "grpcio-1.62.1.tar.gz", hash = "sha256:6c455e008fa86d9e9a9d85bb76da4277c0d7d9668a3bfa70dbe86e9f3c759947"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.62.0)"] +protobuf = ["grpcio-tools (>=1.62.1)"] [[package]] name = "grpcio-tools" -version = "1.62.0" +version = "1.62.1" description = "Protobuf code generator for gRPC" optional = true python-versions = ">=3.7" files = [ - {file = "grpcio-tools-1.62.0.tar.gz", hash = "sha256:7fca6ecfbbf0549058bb29dcc6e435d885b878d07701e77ac58e1e1f591736dc"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:465c51ebaa184ee3bb619cd5bfaf562bbdde166f2822a6935461e6a741f5ac19"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:0d9c9a4832f52c4597d6dc12d9ab3109c3bd0ee1686b8bf6d64f9eab4145e3cb"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:5a482d9625209023481e631c29a6df1392bfc49f9accfa880dabbacff642559a"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74196beed18383d53ff3e2412a6c1eefa3ff109e987be240368496bc3dcabc8b"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aca28cbeb605c59b5689a7e000fbc2bd659d2f322c58461f3912f00069f6da"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:523adf731fa4c5af0bf7ee2edb65e8c7ef4d9df9951461d6a18fe096688efd2d"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:791aa220f8f1936e65bc079e9eb954fa0202a1f16e28b83956e59d17dface127"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-win32.whl", hash = "sha256:5dacc691b18d2c294ea971720ff980a1e2d68a3f7ddcd2f0670b3204e81c4b18"}, - {file = "grpcio_tools-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:6999a4e705b03aacad46e625feb7610e47ec88dbd51220c2282b6334f90721fc"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:19b74e141937c885c9e56b6a7dfa190ca7d583bd48bce9171dd65bbf108b9271"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:17c16e9a89c0b9f4ff2b143f232c5256383453ce7b55fe981598f9517adc8252"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:3730b1cd998a0cffc817602cc55e51f268fa97b3e38fa4bee578e3741474547a"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14201950513636f515dd455a06890e3a21d115b943cf6a8f5af67ad1413cfa1f"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f74e0053360e0eadd75193c0c379b6d7f51d074ebbff856bd41780e1a028b38d"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d5959e3df126931d28cd94dd5f0a708b7dd96019de80ab715fb922fd0c8a838d"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1927934dfba4658a97c2dab267e53ed239264d40fdd5b295fc317693543db85b"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-win32.whl", hash = "sha256:2f5bd22203e64e1732e149bfdd3083716d038abca294e4e2852159b3d893f9ec"}, - {file = "grpcio_tools-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:cd1f4caeca614b04db803566473f7db0971e7a88268f95e4a529b0ace699b949"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f0884eaf6a2bbd7b03fea456e808909ee48dd4f7f455519d67defda791116368"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:6b900ae319b6f9ac1be0ca572dfb41c23a7ff6fcbf36e3be6d3054e1e4c60de6"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:3bbe79b134dfb7c98cf60e4962e31039bef824834cc7034bdf1886a2ed1097f9"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77196c7ac8741d4a2aebb023bcc2964ac65ca44180fd791640889ab2afed3e47"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b65288ebe12e38dd3650fea65d82fcce0d35df1ae4a770b525c10119ee71962f"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52b216c458458f6c292e12428916e80974c5113abc505a61e7b0b9f8932a785d"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88aa62303278aec45bbb26bf679269c7890346c37140ae30e39da1070c341e11"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-win32.whl", hash = "sha256:bb6802d63e42734d2baf02e1343377fe18590ed6a1f5ffbdebbbe0f8331f176b"}, - {file = "grpcio_tools-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:d5652d3a52a2e8e1d9bdf28fbd15e21b166e31b968cd7c8c604bf31611c0bb5b"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:84e27206bd884be83a7fdcef8be3c90eb1591341c0ba9b0d25ec9db1043ba2f2"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:5eb63d9207b02a0fa30216907e1e7705cc2670f933e77236c6e0eb966ad3b4bf"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:95e49839d49e79187c43cd63af5c206dc5743a01d7d3d2f039772fa743cbb30c"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ae5cd2f89e33a529790bf8aa59a459484edb05e4f58d4cf78836b9dfa1fab43"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e1fd7301d762bf5984b7e7fb62fce82cff864d75f0a57e15cfd07ae1bd79133"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e38d5800151e6804d500e329f7ddfb615c50eee0c1607593e3147a4b21037e40"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:563a75924109e75809b2919e68d7e6ae7872e63d20258aae7899b14f6ff9e18b"}, - {file = "grpcio_tools-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8934715577c9cc0c792b8a77f7d0dd2bb60e951161b10c5f46b60856673240"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:ed6cf7ff4a10c46f85340f9c68982f9efb29f51ee4b66828310fcdf3c2d7ffd1"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:1faa5006fe9e7b9e65c47bc23f7cd333fdcdd4ba35d44080303848266db5ab05"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:3b526dc5566161a3a17599753838b9cfbdd4cb15b6ad419aae8a5d12053fa8ae"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09db3688efd3499ce3c0b02c0bac0656abdab4cb99716f81ad879c08b92c56e"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:006ea0cc16e8bf8f307326e0556e1384f24abb402cc4e6a720aa1dfe8f268647"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b46ba0b6552b4375ede65e0c89491af532635347f78d52a72f8a027529e713ed"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ec6f561c86fe13cff3be16f297cc05e1aa1274294524743a4cf91d971866fbb0"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-win32.whl", hash = "sha256:c85391e06620d6e16a56341caae5007d0c6219beba065e1e288f2523fba6a335"}, - {file = "grpcio_tools-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:679cf2507090e010da73e5001665c76de2a5927b2e2110e459222b1c81cb10c2"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:0e87f105f1d152934759f8975ed002d5ce057b3cdf1cc6cb63fe6008671a27b9"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:bf9f281f528e0220558d57e09b4518dec148dcb250d78bd9cbb27e09edabb3f9"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:711314cb4c6c8b3d51bafaee380ffa5012bd0567ed68f1b0b1fc07492b27acab"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54bb570bd963905de3bda596b35e06026552705edebbb2cb737b57aa5252b9e5"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dce5f04676cf94e6e2d13d7f91ac2de79097d86675bc4d404a3c24dcc0332c88"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:98ddf871c614cc0ed331c7159ebbbf5040be562279677d3bb97c2e6083539f72"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f3aaf3b20c0f7063856b2432335af8f76cf580f898e04085548cde28332d6833"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-win32.whl", hash = "sha256:3dee3be61d9032f777a9b4e2696ea3d0748a582cb99c672b5d41ca66821e8c87"}, - {file = "grpcio_tools-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:f54b5181784464bd3573ae7dbcf053da18a4b7a75fe19960791f383be3d035ca"}, + {file = "grpcio-tools-1.62.1.tar.gz", hash = "sha256:a4991e5ee8a97ab791296d3bf7e8700b1445635cc1828cc98df945ca1802d7f2"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:f2b404bcae7e2ef9b0b9803b2a95119eb7507e6dc80ea4a64a78be052c30cebc"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:fdd987a580b4474769adfd40144486f54bcc73838d5ec5d3647a17883ea78e76"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:07af1a6442e2313cff22af93c2c4dd37ae32b5239b38e0d99e2cbf93de65429f"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41384c9ee18e61ef20cad2774ef71bd8854b63efce263b5177aa06fccb84df1f"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c38006f7702d2ff52122e4c77a47348709374050c76216e84b30a9f06e45afa"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08fecc3c5b4e6dd3278f2b9d12837e423c7dcff551ca1e587018b4a0fc5f8019"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a01e8dcd0f041f6fa6d815c54a2017d032950e310c41d514a8bc041e872c4d12"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-win32.whl", hash = "sha256:dd933b8e0b3c13fe3543d58f849a6a5e0d7987688cb6801834278378c724f695"}, + {file = "grpcio_tools-1.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:2b04844a9382f1bde4b4174e476e654ab3976168d2469cb4b29e352f4f35a5aa"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:024380536ba71a96cdf736f0954f6ad03f5da609c09edbcc2ca02fdd639e0eed"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:21f14b99e0cd38ad56754cc0b62b2bf3cf75f9f7fc40647da54669e0da0726fe"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:975ac5fb482c23f3608c16e06a43c8bab4d79c2e2564cdbc25cf753c6e998775"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50739aaab0c8076ad5957204e71f2e0c9876e11fd8338f7f09de12c2d75163c5"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598c54318f0326cf5020aa43fc95a15e933aba4a71943d3bff2677d2d21ddfa1"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f309bdb33a61f8e049480d41498ee2e525cfb5e959958b326abfdf552bf9b9cb"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f358effd3c11d66c150e0227f983d54a5cd30e14038566dadcf25f9f6844e6e8"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-win32.whl", hash = "sha256:b76aead9b73f1650a091870fe4e9ed15ac4d8ed136f962042367255199c23594"}, + {file = "grpcio_tools-1.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:d66a5d47eaa427039752fa0a83a425ff2a487b6a0ac30556fd3be2f3a27a0130"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:575535d039b97d63e6a9abee626d6c7cd47bd8cb73dd00a5c84a98254a2164a4"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:22644c90e43d1a888477899af917979e17364fdd6e9bbb92679cd6a54c4d36c3"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:156d3e1b227c16e903003a56881dbe60e40f2b4bd66f0bc3b27c53e466e6384d"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ad7c5691625a85327e5b683443baf73ae790fd5afc938252041ed5cd665e377"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e140bbc08eea8abf51c0274f45fb1e8350220e64758998d7f3c7f985a0b2496"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7444fcab861911525470d398e5638b70d5cbea3b4674a3de92b5c58c5c515d4d"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e643cd14a5d1e59865cba68a5a6f0175d987f36c5f4cb0db80dee9ed60b4c174"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-win32.whl", hash = "sha256:1344a773d2caa9bb7fbea7e879b84f33740c808c34a5bd2a2768e526117a6b44"}, + {file = "grpcio_tools-1.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:2eea1db3748b2f37b4dce84d8e0c15d9bc811094807cabafe7b0ea47f424dfd5"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:45d2e6cf04d27286b6f73e6e20ba3f0a1f6d8f5535e5dcb1356200419bb457f4"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:46ae58e6926773e7315e9005f0f17aacedbc0895a8752bec087d24efa2f1fb21"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:4c28086df31478023a36f45e50767872ab3aed2419afff09814cb61c88b77db4"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4fba5b339f4797548591036c9481e6895bf920fab7d3dc664d2697f8fb7c0bf"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23eb3d47f78f509fcd201749b1f1e44b76f447913f7fbb3b8bae20f109086295"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fd5d47707bd6bc2b707ece765c362d2a1d2e8f6cd92b04c99fab49a929f3610c"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d1924a6a943df7c73b9ef0048302327c75962b567451479710da729ead241228"}, + {file = "grpcio_tools-1.62.1-cp37-cp37m-win_amd64.whl", hash = "sha256:fe71ca30aabe42591e84ecb9694c0297dc699cc20c5b24d2cb267fb0fc01f947"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:1819fd055c1ae672d1d725ec75eefd1f700c18acba0ed9332202be31d69c401d"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:5dbe1f7481dd14b6d477b4bace96d275090bc7636b9883975a08b802c94e7b78"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:771c051c5ece27ad03e4f2e33624a925f0ad636c01757ab7dbb04a37964af4ba"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98209c438b38b6f1276dbc27b1c04e346a75bfaafe72a25a548f2dc5ce71d226"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2152308e5321cb90fb45aaa84d03d6dedb19735a8779aaf36c624f97b831842d"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ed1f27dc2b2262c8b8d9036276619c1bb18791311c16ccbf1f31b660f2aad7cf"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2744947b6c5e907af21133431809ccca535a037356864e32c122efed8cb9de1f"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-win32.whl", hash = "sha256:13b20e269d14ad629ff9a2c9a2450f3dbb119d5948de63b27ffe624fa7aea85a"}, + {file = "grpcio_tools-1.62.1-cp38-cp38-win_amd64.whl", hash = "sha256:999823758e9eacd0095863d06cd6d388be769f80c9abb65cdb11c4f2cfce3fea"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:941f8a5c31986053e75fa466bcfa743c2bf1b513b7978cf1f4ab4e96a8219d27"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b9c02c88c77ef6057c6cbeea8922d7c2424aabf46bfc40ddf42a32765ba91061"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:6abd4eb3ccb444383a40156139acc3aaa73745d395139cb6bc8e2a3429e1e627"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:449503213d142f8470b331a1c2f346f8457f16c7fe20f531bc2500e271f7c14c"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a11bcf609d00cfc9baed77ab308223cabc1f0b22a05774a26dd4c94c0c80f1f"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5d7bdea33354b55acf40bb4dd3ba7324d6f1ef6b4a1a4da0807591f8c7e87b9a"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d03b645852d605f43003020e78fe6d573cae6ee6b944193e36b8b317e7549a20"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-win32.whl", hash = "sha256:52b185dfc3bf32e70929310367dbc66185afba60492a6a75a9b1141d407e160c"}, + {file = "grpcio_tools-1.62.1-cp39-cp39-win_amd64.whl", hash = "sha256:63a273b70896d3640b7a883eb4a080c3c263d91662d870a2e9c84b7bbd978e7b"}, ] [package.dependencies] -grpcio = ">=1.62.0" +grpcio = ">=1.62.1" protobuf = ">=4.21.6,<5.0dev" setuptools = "*" @@ -1559,13 +1593,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" -version = "0.20.3" +version = "0.21.4" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.20.3-py3-none-any.whl", hash = "sha256:d988ae4f00d3e307b0c80c6a05ca6dbb7edba8bba3079f74cda7d9c2e562a7b6"}, - {file = "huggingface_hub-0.20.3.tar.gz", hash = "sha256:94e7f8e074475fbc67d6a71957b678e1b4a74ff1b64a644fd6cbb83da962d05d"}, + {file = "huggingface_hub-0.21.4-py3-none-any.whl", hash = "sha256:df37c2c37fc6c82163cdd8a67ede261687d80d1e262526d6c0ce73b6b3630a7b"}, + {file = "huggingface_hub-0.21.4.tar.gz", hash = "sha256:e1f4968c93726565a80edf6dc309763c7b546d0cfe79aa221206034d50155531"}, ] [package.dependencies] @@ -1582,11 +1616,12 @@ all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", cli = ["InquirerPy (==0.3.4)"] dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] +hf-transfer = ["hf-transfer (>=0.1.4)"] inference = ["aiohttp", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)"] quality = ["mypy (==1.5.1)", "ruff (>=0.1.3)"] tensorflow = ["graphviz", "pydot", "tensorflow"] testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] -torch = ["torch"] +torch = ["safetensors", "torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] [[package]] @@ -1638,32 +1673,32 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "7.0.2" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, - {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, + {file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"}, + {file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "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"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.1.2" +version = "6.1.3" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.2-py3-none-any.whl", hash = "sha256:9a0a862501dc38b68adebc82970140c9e4209fc99601782925178f8386339938"}, - {file = "importlib_resources-6.1.2.tar.gz", hash = "sha256:308abf8474e2dba5f867d279237cd4076482c3de7104a40b41426370e891549b"}, + {file = "importlib_resources-6.1.3-py3-none-any.whl", hash = "sha256:4c0269e3580fe2634d364b39b38b961540a7738c02cb984e98add8b4221d793d"}, + {file = "importlib_resources-6.1.3.tar.gz", hash = "sha256:56fb4525197b78544a3354ea27793952ab93f935bb4bf746b846bb1015020f2b"}, ] [package.dependencies] @@ -1671,7 +1706,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +testing = ["jaraco.collections", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -1686,13 +1721,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.29.2" +version = "6.29.3" description = "IPython Kernel for Jupyter" optional = true python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.2-py3-none-any.whl", hash = "sha256:50384f5c577a260a1d53f1f59a828c7266d321c9b7d00d345693783f66616055"}, - {file = "ipykernel-6.29.2.tar.gz", hash = "sha256:3bade28004e3ff624ed57974948116670604ac5f676d12339693f3142176d3f0"}, + {file = "ipykernel-6.29.3-py3-none-any.whl", hash = "sha256:5aa086a4175b0229d4eca211e181fb473ea78ffd9869af36ba7694c947302a21"}, + {file = "ipykernel-6.29.3.tar.gz", hash = "sha256:e14c250d1f9ea3989490225cc1a542781b095a18a19447fcf2b5eaf7d0ac5bd2"}, ] [package.dependencies] @@ -1715,7 +1750,7 @@ cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] pyqt5 = ["pyqt5"] pyside6 = ["pyside6"] -test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (==0.23.4)", "pytest-cov", "pytest-timeout"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] [[package]] name = "ipython" @@ -2249,17 +2284,18 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp [[package]] name = "mkdocs-autorefs" -version = "0.5.0" +version = "1.0.1" description = "Automatically link across pages in MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_autorefs-0.5.0-py3-none-any.whl", hash = "sha256:7930fcb8ac1249f10e683967aeaddc0af49d90702af111a5e390e8b20b3d97ff"}, - {file = "mkdocs_autorefs-0.5.0.tar.gz", hash = "sha256:9a5054a94c08d28855cfab967ada10ed5be76e2bfad642302a610b252c3274c0"}, + {file = "mkdocs_autorefs-1.0.1-py3-none-any.whl", hash = "sha256:aacdfae1ab197780fb7a2dac92ad8a3d8f7ca8049a9cbe56a4218cd52e8da570"}, + {file = "mkdocs_autorefs-1.0.1.tar.gz", hash = "sha256:f684edf847eced40b570b57846b15f0bf57fb93ac2c510450775dcf16accb971"}, ] [package.dependencies] Markdown = ">=3.3" +markupsafe = ">=2.0.1" mkdocs = ">=1.1" [[package]] @@ -2278,13 +2314,13 @@ mkdocs = ">=1.0.3" [[package]] name = "mkdocs-material" -version = "9.5.11" +version = "9.5.13" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.11-py3-none-any.whl", hash = "sha256:788ee0f3e036dca2dc20298d65e480297d348a44c9d7b2ee05c5262983e66072"}, - {file = "mkdocs_material-9.5.11.tar.gz", hash = "sha256:7af7f8af0dea16175558f3fb9245d26c83a17199baa5f157755e63d7437bf971"}, + {file = "mkdocs_material-9.5.13-py3-none-any.whl", hash = "sha256:5cbe17fee4e3b4980c8420a04cc762d8dc052ef1e10532abd4fce88e5ea9ce6a"}, + {file = "mkdocs_material-9.5.13.tar.gz", hash = "sha256:d8e4caae576312a88fd2609b81cf43d233cdbe36860d67a68702b018b425bd87"}, ] [package.dependencies] @@ -2318,13 +2354,13 @@ files = [ [[package]] name = "mkdocstrings" -version = "0.24.0" +version = "0.24.1" description = "Automatic documentation from sources, for MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings-0.24.0-py3-none-any.whl", hash = "sha256:f4908560c10f587326d8f5165d1908817b2e280bbf707607f601c996366a2264"}, - {file = "mkdocstrings-0.24.0.tar.gz", hash = "sha256:222b1165be41257b494a9d29b14135d2b7ca43f38161d5b10caae03b87bd4f7e"}, + {file = "mkdocstrings-0.24.1-py3-none-any.whl", hash = "sha256:b4206f9a2ca8a648e222d5a0ca1d36ba7dee53c88732818de183b536f9042b5d"}, + {file = "mkdocstrings-0.24.1.tar.gz", hash = "sha256:cc83f9a1c8724fc1be3c2fa071dd73d91ce902ef6a79710249ec8d0ee1064401"}, ] [package.dependencies] @@ -3112,13 +3148,13 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p [[package]] name = "posthog" -version = "3.4.2" +version = "3.5.0" description = "Integrate PostHog into any python application." optional = true python-versions = "*" files = [ - {file = "posthog-3.4.2-py2.py3-none-any.whl", hash = "sha256:c7e79b2e585d16e93749874bcbcdad78d857037398ce0d8d6c474a04d0bd3bbe"}, - {file = "posthog-3.4.2.tar.gz", hash = "sha256:f0eafa663fbc4a942b49b6168a62a890635407044bbc7593051dcb9cc1208873"}, + {file = "posthog-3.5.0-py2.py3-none-any.whl", hash = "sha256:3c672be7ba6f95d555ea207d4486c171d06657eb34b3ce25eb043bfe7b6b5b76"}, + {file = "posthog-3.5.0.tar.gz", hash = "sha256:8f7e3b2c6e8714d0c0c542a2109b83a7549f63b7113a133ab2763a89245ef2ef"}, ] [package.dependencies] @@ -3280,47 +3316,47 @@ files = [ [[package]] name = "pyarrow" -version = "15.0.0" +version = "15.0.1" description = "Python library for Apache Arrow" optional = false python-versions = ">=3.8" files = [ - {file = "pyarrow-15.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0a524532fd6dd482edaa563b686d754c70417c2f72742a8c990b322d4c03a15d"}, - {file = "pyarrow-15.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:60a6bdb314affa9c2e0d5dddf3d9cbb9ef4a8dddaa68669975287d47ece67642"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66958fd1771a4d4b754cd385835e66a3ef6b12611e001d4e5edfcef5f30391e2"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f500956a49aadd907eaa21d4fff75f73954605eaa41f61cb94fb008cf2e00c6"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6f87d9c4f09e049c2cade559643424da84c43a35068f2a1c4653dc5b1408a929"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85239b9f93278e130d86c0e6bb455dcb66fc3fd891398b9d45ace8799a871a1e"}, - {file = "pyarrow-15.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b8d43e31ca16aa6e12402fcb1e14352d0d809de70edd185c7650fe80e0769e3"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:fa7cd198280dbd0c988df525e50e35b5d16873e2cdae2aaaa6363cdb64e3eec5"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8780b1a29d3c8b21ba6b191305a2a607de2e30dab399776ff0aa09131e266340"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0ec198ccc680f6c92723fadcb97b74f07c45ff3fdec9dd765deb04955ccf19"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036a7209c235588c2f07477fe75c07e6caced9b7b61bb897c8d4e52c4b5f9555"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bd8a0e5296797faf9a3294e9fa2dc67aa7f10ae2207920dbebb785c77e9dbe5"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e8ebed6053dbe76883a822d4e8da36860f479d55a762bd9e70d8494aed87113e"}, - {file = "pyarrow-15.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d53a9d1b2b5bd7d5e4cd84d018e2a45bc9baaa68f7e6e3ebed45649900ba99"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9950a9c9df24090d3d558b43b97753b8f5867fb8e521f29876aa021c52fda351"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:003d680b5e422d0204e7287bb3fa775b332b3fce2996aa69e9adea23f5c8f970"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f75fce89dad10c95f4bf590b765e3ae98bcc5ba9f6ce75adb828a334e26a3d40"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca9cb0039923bec49b4fe23803807e4ef39576a2bec59c32b11296464623dc2"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ed5a78ed29d171d0acc26a305a4b7f83c122d54ff5270810ac23c75813585e4"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6eda9e117f0402dfcd3cd6ec9bfee89ac5071c48fc83a84f3075b60efa96747f"}, - {file = "pyarrow-15.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a3a6180c0e8f2727e6f1b1c87c72d3254cac909e609f35f22532e4115461177"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:19a8918045993349b207de72d4576af0191beef03ea655d8bdb13762f0cd6eac"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0ec076b32bacb6666e8813a22e6e5a7ef1314c8069d4ff345efa6246bc38593"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5db1769e5d0a77eb92344c7382d6543bea1164cca3704f84aa44e26c67e320fb"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2617e3bf9df2a00020dd1c1c6dce5cc343d979efe10bc401c0632b0eef6ef5b"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:d31c1d45060180131caf10f0f698e3a782db333a422038bf7fe01dace18b3a31"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:c8c287d1d479de8269398b34282e206844abb3208224dbdd7166d580804674b7"}, - {file = "pyarrow-15.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:07eb7f07dc9ecbb8dace0f58f009d3a29ee58682fcdc91337dfeb51ea618a75b"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:47af7036f64fce990bb8a5948c04722e4e3ea3e13b1007ef52dfe0aa8f23cf7f"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93768ccfff85cf044c418bfeeafce9a8bb0cee091bd8fd19011aff91e58de540"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ee87fd6892700960d90abb7b17a72a5abb3b64ee0fe8db6c782bcc2d0dc0b4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:001fca027738c5f6be0b7a3159cc7ba16a5c52486db18160909a0831b063c4e4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:d1c48648f64aec09accf44140dccb92f4f94394b8d79976c426a5b79b11d4fa7"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:972a0141be402bb18e3201448c8ae62958c9c7923dfaa3b3d4530c835ac81aed"}, - {file = "pyarrow-15.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:f01fc5cf49081426429127aa2d427d9d98e1cb94a32cb961d583a70b7c4504e6"}, - {file = "pyarrow-15.0.0.tar.gz", hash = "sha256:876858f549d540898f927eba4ef77cd549ad8d24baa3207cf1b72e5788b50e83"}, + {file = "pyarrow-15.0.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:c2ddb3be5ea938c329a84171694fc230b241ce1b6b0ff1a0280509af51c375fa"}, + {file = "pyarrow-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7543ea88a0ff72f8e6baaf9bfdbec2c62aeabdbede9e4a571c71cc3bc43b6302"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1519e218a6941fc074e4501088d891afcb2adf77c236e03c34babcf3d6a0d1c7"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28cafa86e1944761970d3b3fc0411b14ff9b5c2b73cd22aaf470d7a3976335f5"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:be5c3d463e33d03eab496e1af7916b1d44001c08f0f458ad27dc16093a020638"}, + {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:47b1eda15d3aa3f49a07b1808648e1397e5dc6a80a30bf87faa8e2d02dad7ac3"}, + {file = "pyarrow-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e524a31be7db22deebbbcf242b189063ab9a7652c62471d296b31bc6e3cae77b"}, + {file = "pyarrow-15.0.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:a476fefe8bdd56122fb0d4881b785413e025858803cc1302d0d788d3522b374d"}, + {file = "pyarrow-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:309e6191be385f2e220586bfdb643f9bb21d7e1bc6dd0a6963dc538e347b2431"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83bc586903dbeb4365cbc72b602f99f70b96c5882e5dfac5278813c7d624ca3c"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e652daac6d8b05280cd2af31c0fb61a4490ec6a53dc01588014d9fa3fdbee9"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:abad2e08652df153a72177ce20c897d083b0c4ebeec051239e2654ddf4d3c996"}, + {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cde663352bc83ad75ba7b3206e049ca1a69809223942362a8649e37bd22f9e3b"}, + {file = "pyarrow-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1b6e237dd7a08482a8b8f3f6512d258d2460f182931832a8c6ef3953203d31e1"}, + {file = "pyarrow-15.0.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:7bd167536ee23192760b8c731d39b7cfd37914c27fd4582335ffd08450ff799d"}, + {file = "pyarrow-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7c08bb31eb2984ba5c3747d375bb522e7e536b8b25b149c9cb5e1c49b0ccb736"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0f9c1d630ed2524bd1ddf28ec92780a7b599fd54704cd653519f7ff5aec177a"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5186048493395220550bca7b524420471aac2d77af831f584ce132680f55c3df"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:31dc30c7ec8958da3a3d9f31d6c3630429b2091ede0ecd0d989fd6bec129f0e4"}, + {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3f111a014fb8ac2297b43a74bf4495cc479a332908f7ee49cb7cbd50714cb0c1"}, + {file = "pyarrow-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a6d1f7c15d7f68f08490d0cb34611497c74285b8a6bbeab4ef3fc20117310983"}, + {file = "pyarrow-15.0.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:9ad931b996f51c2f978ed517b55cb3c6078272fb4ec579e3da5a8c14873b698d"}, + {file = "pyarrow-15.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:738f6b53ab1c2f66b2bde8a1d77e186aeaab702d849e0dfa1158c9e2c030add3"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c1c3fc16bc74e33bf8f1e5a212938ed8d88e902f372c4dac6b5bad328567d2f"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1fa92512128f6c1b8dde0468c1454dd70f3bff623970e370d52efd4d24fd0be"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:b4157f307c202cbbdac147d9b07447a281fa8e63494f7fc85081da351ec6ace9"}, + {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:b75e7da26f383787f80ad76143b44844ffa28648fcc7099a83df1538c078d2f2"}, + {file = "pyarrow-15.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:3a99eac76ae14096c209850935057b9e8ce97a78397c5cde8724674774f34e5d"}, + {file = "pyarrow-15.0.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:dd532d3177e031e9b2d2df19fd003d0cc0520d1747659fcabbd4d9bb87de508c"}, + {file = "pyarrow-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ce8c89848fd37e5313fc2ce601483038ee5566db96ba0808d5883b2e2e55dc53"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:862eac5e5f3b6477f7a92b2f27e560e1f4e5e9edfca9ea9da8a7478bb4abd5ce"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f0ea3a29cd5cb99bf14c1c4533eceaa00ea8fb580950fb5a89a5c771a994a4e"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:bb902f780cfd624b2e8fd8501fadab17618fdb548532620ef3d91312aaf0888a"}, + {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:4f87757f02735a6bb4ad2e1b98279ac45d53b748d5baf52401516413007c6999"}, + {file = "pyarrow-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:efd3816c7fbfcbd406ac0f69873cebb052effd7cdc153ae5836d1b00845845d7"}, + {file = "pyarrow-15.0.1.tar.gz", hash = "sha256:21d812548d39d490e0c6928a7c663f37b96bf764034123d4b4ab4530ecc757a9"}, ] [package.dependencies] @@ -3541,13 +3577,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.7" +version = "10.7.1" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.7-py3-none-any.whl", hash = "sha256:6ca215bc57bc12bf32b414887a68b810637d039124ed9b2e5bd3325cbb2c050c"}, - {file = "pymdown_extensions-10.7.tar.gz", hash = "sha256:c0d64d5cf62566f59e6b2b690a4095c931107c250a8c8e1351c1de5f6b036deb"}, + {file = "pymdown_extensions-10.7.1-py3-none-any.whl", hash = "sha256:f5cc7000d7ff0d1ce9395d216017fa4df3dde800afb1fb72d1c7d3fd35e710f4"}, + {file = "pymdown_extensions-10.7.1.tar.gz", hash = "sha256:c70e146bdd83c744ffc766b4671999796aba18842b268510a329f7f64700d584"}, ] [package.dependencies] @@ -3559,13 +3595,13 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pyparsing" -version = "3.1.1" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -3618,13 +3654,13 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" 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"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -3859,13 +3895,13 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "qdrant-client" -version = "1.7.3" +version = "1.8.0" description = "Client library for the Qdrant vector search engine" optional = true python-versions = ">=3.8" files = [ - {file = "qdrant_client-1.7.3-py3-none-any.whl", hash = "sha256:b062420ba55eb847652c7d2a26404fb1986bea13aa785763024013f96a7a915c"}, - {file = "qdrant_client-1.7.3.tar.gz", hash = "sha256:7b809be892cdc5137ae80ea3335da40c06499ad0b0072b5abc6bad79da1d29fc"}, + {file = "qdrant_client-1.8.0-py3-none-any.whl", hash = "sha256:fa28d3eb64c0c57ec029c7c85c71f6c72c197f92502022655741f3632c518e29"}, + {file = "qdrant_client-1.8.0.tar.gz", hash = "sha256:2a1a3f2cbacc7adba85644cf6cfdee20401cf25764b32da479c81fb63e178d15"}, ] [package.dependencies] @@ -3878,7 +3914,7 @@ pydantic = ">=1.10.8" urllib3 = ">=1.26.14,<3" [package.extras] -fastembed = ["fastembed (==0.1.1)"] +fastembed = ["fastembed (==0.2.2)"] [[package]] name = "referencing" @@ -4450,60 +4486,60 @@ test = ["pytest"] [[package]] name = "sqlalchemy" -version = "2.0.27" +version = "2.0.28" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d04e579e911562f1055d26dab1868d3e0bb905db3bccf664ee8ad109f035618a"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa67d821c1fd268a5a87922ef4940442513b4e6c377553506b9db3b83beebbd8"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c7a596d0be71b7baa037f4ac10d5e057d276f65a9a611c46970f012752ebf2d"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954d9735ee9c3fa74874c830d089a815b7b48df6f6b6e357a74130e478dbd951"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5cd20f58c29bbf2680039ff9f569fa6d21453fbd2fa84dbdb4092f006424c2e6"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:03f448ffb731b48323bda68bcc93152f751436ad6037f18a42b7e16af9e91c07"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win32.whl", hash = "sha256:d997c5938a08b5e172c30583ba6b8aad657ed9901fc24caf3a7152eeccb2f1b4"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win_amd64.whl", hash = "sha256:eb15ef40b833f5b2f19eeae65d65e191f039e71790dd565c2af2a3783f72262f"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c5bad7c60a392850d2f0fee8f355953abaec878c483dd7c3836e0089f046bf6"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3012ab65ea42de1be81fff5fb28d6db893ef978950afc8130ba707179b4284a"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbcd77c4d94b23e0753c5ed8deba8c69f331d4fd83f68bfc9db58bc8983f49cd"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d177b7e82f6dd5e1aebd24d9c3297c70ce09cd1d5d37b43e53f39514379c029c"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:680b9a36029b30cf063698755d277885d4a0eab70a2c7c6e71aab601323cba45"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1306102f6d9e625cebaca3d4c9c8f10588735ef877f0360b5cdb4fdfd3fd7131"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win32.whl", hash = "sha256:5b78aa9f4f68212248aaf8943d84c0ff0f74efc65a661c2fc68b82d498311fd5"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win_amd64.whl", hash = "sha256:15e19a84b84528f52a68143439d0c7a3a69befcd4f50b8ef9b7b69d2628ae7c4"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0de1263aac858f288a80b2071990f02082c51d88335a1db0d589237a3435fe71"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce850db091bf7d2a1f2fdb615220b968aeff3849007b1204bf6e3e50a57b3d32"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dfc936870507da96aebb43e664ae3a71a7b96278382bcfe84d277b88e379b18"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4fbe6a766301f2e8a4519f4500fe74ef0a8509a59e07a4085458f26228cd7cc"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4535c49d961fe9a77392e3a630a626af5baa967172d42732b7a43496c8b28876"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0fb3bffc0ced37e5aa4ac2416f56d6d858f46d4da70c09bb731a246e70bff4d5"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win32.whl", hash = "sha256:7f470327d06400a0aa7926b375b8e8c3c31d335e0884f509fe272b3c700a7254"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win_amd64.whl", hash = "sha256:f9374e270e2553653d710ece397df67db9d19c60d2647bcd35bfc616f1622dcd"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e97cf143d74a7a5a0f143aa34039b4fecf11343eed66538610debc438685db4a"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7b5a3e2120982b8b6bd1d5d99e3025339f7fb8b8267551c679afb39e9c7c7f1"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e36aa62b765cf9f43a003233a8c2d7ffdeb55bc62eaa0a0380475b228663a38f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5ada0438f5b74c3952d916c199367c29ee4d6858edff18eab783b3978d0db16d"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b1d9d1bfd96eef3c3faedb73f486c89e44e64e40e5bfec304ee163de01cf996f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win32.whl", hash = "sha256:ca891af9f3289d24a490a5fde664ea04fe2f4984cd97e26de7442a4251bd4b7c"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win_amd64.whl", hash = "sha256:fd8aafda7cdff03b905d4426b714601c0978725a19efc39f5f207b86d188ba01"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec1f5a328464daf7a1e4e385e4f5652dd9b1d12405075ccba1df842f7774b4fc"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad862295ad3f644e3c2c0d8b10a988e1600d3123ecb48702d2c0f26771f1c396"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48217be1de7d29a5600b5c513f3f7664b21d32e596d69582be0a94e36b8309cb"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e56afce6431450442f3ab5973156289bd5ec33dd618941283847c9fd5ff06bf"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:611068511b5531304137bcd7fe8117c985d1b828eb86043bd944cebb7fae3910"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b86abba762ecfeea359112b2bb4490802b340850bbee1948f785141a5e020de8"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win32.whl", hash = "sha256:30d81cc1192dc693d49d5671cd40cdec596b885b0ce3b72f323888ab1c3863d5"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win_amd64.whl", hash = "sha256:120af1e49d614d2525ac247f6123841589b029c318b9afbfc9e2b70e22e1827d"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d07ee7793f2aeb9b80ec8ceb96bc8cc08a2aec8a1b152da1955d64e4825fcbac"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb0845e934647232b6ff5150df37ceffd0b67b754b9fdbb095233deebcddbd4a"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc19ae2e07a067663dd24fca55f8ed06a288384f0e6e3910420bf4b1270cc51"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b90053be91973a6fb6020a6e44382c97739736a5a9d74e08cc29b196639eb979"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2f5c9dfb0b9ab5e3a8a00249534bdd838d943ec4cfb9abe176a6c33408430230"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33e8bde8fff203de50399b9039c4e14e42d4d227759155c21f8da4a47fc8053c"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win32.whl", hash = "sha256:d873c21b356bfaf1589b89090a4011e6532582b3a8ea568a00e0c3aab09399dd"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win_amd64.whl", hash = "sha256:ff2f1b7c963961d41403b650842dc2039175b906ab2093635d8319bef0b7d620"}, - {file = "SQLAlchemy-2.0.27-py3-none-any.whl", hash = "sha256:1ab4e0448018d01b142c916cc7119ca573803a4745cfe341b8f95657812700ac"}, - {file = "SQLAlchemy-2.0.27.tar.gz", hash = "sha256:86a6ed69a71fe6b88bf9331594fa390a2adda4a49b5c06f98e47bf0d392534f8"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0b148ab0438f72ad21cb004ce3bdaafd28465c4276af66df3b9ecd2037bf252"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbda76961eb8f27e6ad3c84d1dc56d5bc61ba8f02bd20fcf3450bd421c2fcc9c"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feea693c452d85ea0015ebe3bb9cd15b6f49acc1a31c28b3c50f4db0f8fb1e71"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5da98815f82dce0cb31fd1e873a0cb30934971d15b74e0d78cf21f9e1b05953f"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a5adf383c73f2d49ad15ff363a8748319ff84c371eed59ffd0127355d6ea1da"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56856b871146bfead25fbcaed098269d90b744eea5cb32a952df00d542cdd368"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-win32.whl", hash = "sha256:943aa74a11f5806ab68278284a4ddd282d3fb348a0e96db9b42cb81bf731acdc"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-win_amd64.whl", hash = "sha256:c6c4da4843e0dabde41b8f2e8147438330924114f541949e6318358a56d1875a"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46a3d4e7a472bfff2d28db838669fc437964e8af8df8ee1e4548e92710929adc"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3dd67b5d69794cfe82862c002512683b3db038b99002171f624712fa71aeaa"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61e2e41656a673b777e2f0cbbe545323dbe0d32312f590b1bc09da1de6c2a02"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0315d9125a38026227f559488fe7f7cee1bd2fbc19f9fd637739dc50bb6380b2"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af8ce2d31679006e7b747d30a89cd3ac1ec304c3d4c20973f0f4ad58e2d1c4c9"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:81ba314a08c7ab701e621b7ad079c0c933c58cdef88593c59b90b996e8b58fa5"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-win32.whl", hash = "sha256:1ee8bd6d68578e517943f5ebff3afbd93fc65f7ef8f23becab9fa8fb315afb1d"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-win_amd64.whl", hash = "sha256:ad7acbe95bac70e4e687a4dc9ae3f7a2f467aa6597049eeb6d4a662ecd990bb6"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d3499008ddec83127ab286c6f6ec82a34f39c9817f020f75eca96155f9765097"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9b66fcd38659cab5d29e8de5409cdf91e9986817703e1078b2fdaad731ea66f5"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea30da1e76cb1acc5b72e204a920a3a7678d9d52f688f087dc08e54e2754c67"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:124202b4e0edea7f08a4db8c81cc7859012f90a0d14ba2bf07c099aff6e96462"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e23b88c69497a6322b5796c0781400692eca1ae5532821b39ce81a48c395aae9"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b6303bfd78fb3221847723104d152e5972c22367ff66edf09120fcde5ddc2e2"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-win32.whl", hash = "sha256:a921002be69ac3ab2cf0c3017c4e6a3377f800f1fca7f254c13b5f1a2f10022c"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-win_amd64.whl", hash = "sha256:b4a2cf92995635b64876dc141af0ef089c6eea7e05898d8d8865e71a326c0385"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e91b5e341f8c7f1e5020db8e5602f3ed045a29f8e27f7f565e0bdee3338f2c7"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c7b78dfc7278329f27be02c44abc0d69fe235495bb8e16ec7ef1b1a17952db"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eba73ef2c30695cb7eabcdb33bb3d0b878595737479e152468f3ba97a9c22a4"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5df5d1dafb8eee89384fb7a1f79128118bc0ba50ce0db27a40750f6f91aa99d5"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2858bbab1681ee5406650202950dc8f00e83b06a198741b7c656e63818633526"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-win32.whl", hash = "sha256:9461802f2e965de5cff80c5a13bc945abea7edaa1d29360b485c3d2b56cdb075"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-win_amd64.whl", hash = "sha256:a6bec1c010a6d65b3ed88c863d56b9ea5eeefdf62b5e39cafd08c65f5ce5198b"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:843a882cadebecc655a68bd9a5b8aa39b3c52f4a9a5572a3036fb1bb2ccdc197"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dbb990612c36163c6072723523d2be7c3eb1517bbdd63fe50449f56afafd1133"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7e4baf9161d076b9a7e432fce06217b9bd90cfb8f1d543d6e8c4595627edb9"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0a5354cb4de9b64bccb6ea33162cb83e03dbefa0d892db88a672f5aad638a75"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fffcc8edc508801ed2e6a4e7b0d150a62196fd28b4e16ab9f65192e8186102b6"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aca7b6d99a4541b2ebab4494f6c8c2f947e0df4ac859ced575238e1d6ca5716b"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-win32.whl", hash = "sha256:8c7f10720fc34d14abad5b647bc8202202f4948498927d9f1b4df0fb1cf391b7"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-win_amd64.whl", hash = "sha256:243feb6882b06a2af68ecf4bec8813d99452a1b62ba2be917ce6283852cf701b"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc4974d3684f28b61b9a90fcb4c41fb340fd4b6a50c04365704a4da5a9603b05"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87724e7ed2a936fdda2c05dbd99d395c91ea3c96f029a033a4a20e008dd876bf"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68722e6a550f5de2e3cfe9da6afb9a7dd15ef7032afa5651b0f0c6b3adb8815d"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:328529f7c7f90adcd65aed06a161851f83f475c2f664a898af574893f55d9e53"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:df40c16a7e8be7413b885c9bf900d402918cc848be08a59b022478804ea076b8"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:426f2fa71331a64f5132369ede5171c52fd1df1bd9727ce621f38b5b24f48750"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-win32.whl", hash = "sha256:33157920b233bc542ce497a81a2e1452e685a11834c5763933b440fedd1d8e2d"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-win_amd64.whl", hash = "sha256:2f60843068e432311c886c5f03c4664acaef507cf716f6c60d5fde7265be9d7b"}, + {file = "SQLAlchemy-2.0.28-py3-none-any.whl", hash = "sha256:78bb7e8da0183a8301352d569900d9d3594c48ac21dc1c2ec6b3121ed8b6c986"}, + {file = "SQLAlchemy-2.0.28.tar.gz", hash = "sha256:dd53b6c4e6d960600fd6532b79ee28e2da489322fcf6648738134587faf767b6"}, ] [package.dependencies] @@ -4870,13 +4906,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.27.1" +version = "0.28.0" description = "The lightning-fast ASGI server." optional = true python-versions = ">=3.8" files = [ - {file = "uvicorn-0.27.1-py3-none-any.whl", hash = "sha256:5c89da2f3895767472a35556e539fd59f7edbe9b1e9c0e1c99eebeadc61838e4"}, - {file = "uvicorn-0.27.1.tar.gz", hash = "sha256:3d9a267296243532db80c83a959a3400502165ade2c1338dea4e67915fd4745a"}, + {file = "uvicorn-0.28.0-py3-none-any.whl", hash = "sha256:6623abbbe6176204a4226e67607b4d52cc60ff62cda0ff177613645cefa2ece1"}, + {file = "uvicorn-0.28.0.tar.gz", hash = "sha256:cab4473b5d1eaeb5a0f6375ac4bc85007ffc75c3cc1768816d9e5d589857b067"}, ] [package.dependencies] @@ -5568,4 +5604,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "8b4cc583653becb3be9f5bc4c34cdf5ced146ba32157a5bb4bdc7885291c0403" +content-hash = "f7a5ab7c85e79920d41e45e9bbd17f0dbc1180c52d027235a656c270d9e79346" From d078598ea733ecb0c753e0840d0dc337c80630c0 Mon Sep 17 00:00:00 2001 From: Isaac Miller Date: Sat, 9 Mar 2024 14:18:17 -0600 Subject: [PATCH 70/79] Revert "Update poetry.lock" This reverts commit e7443d65f634dbd834e4f38e9980a7967237c0ac. --- poetry.lock | 572 ++++++++++++++++++++++++---------------------------- 1 file changed, 268 insertions(+), 304 deletions(-) diff --git a/poetry.lock b/poetry.lock index 670e11592..30ec76981 100644 --- a/poetry.lock +++ b/poetry.lock @@ -151,30 +151,6 @@ files = [ {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] -[[package]] -name = "anthropic" -version = "0.18.1" -description = "The official Python library for the anthropic API" -optional = true -python-versions = ">=3.7" -files = [ - {file = "anthropic-0.18.1-py3-none-any.whl", hash = "sha256:b85aee64f619ce1b1964ba733a09adc4053e7bc4e6d4186001229ec191099dcf"}, - {file = "anthropic-0.18.1.tar.gz", hash = "sha256:f5d1caafd43f6cc933a79753a93531605095f040a384f6a900c3de9c3fb6694e"}, -] - -[package.dependencies] -anyio = ">=3.5.0,<5" -distro = ">=1.7.0,<2" -httpx = ">=0.23.0,<1" -pydantic = ">=1.9.0,<3" -sniffio = "*" -tokenizers = ">=0.13.0" -typing-extensions = ">=4.7,<5" - -[package.extras] -bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] -vertex = ["google-auth (>=2,<3)"] - [[package]] name = "anyio" version = "4.3.0" @@ -390,13 +366,13 @@ lxml = ["lxml"] [[package]] name = "cachetools" -version = "5.3.3" +version = "5.3.2" description = "Extensible memoizing collections and decorators" optional = true python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, - {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, + {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, + {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, ] [[package]] @@ -779,20 +755,20 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "datasets" -version = "2.18.0" +version = "2.17.1" description = "HuggingFace community-driven open-source library of datasets" optional = false python-versions = ">=3.8.0" files = [ - {file = "datasets-2.18.0-py3-none-any.whl", hash = "sha256:f1bbf0e2896917a914de01cbd37075b14deea3837af87ad0d9f697388ccaeb50"}, - {file = "datasets-2.18.0.tar.gz", hash = "sha256:cdf8b8c6abf7316377ba4f49f9589a4c74556d6b481afd0abd2284f3d69185cb"}, + {file = "datasets-2.17.1-py3-none-any.whl", hash = "sha256:346974daf2fe9c14ddb35646896b2308b95e7dc27709d1a6e25273573b140cf8"}, + {file = "datasets-2.17.1.tar.gz", hash = "sha256:66ec24077807f374f379b62ab0256c4dcb7c38a57ff1529a22993e8d95f2f9f1"}, ] [package.dependencies] aiohttp = "*" dill = ">=0.3.0,<0.3.9" filelock = "*" -fsspec = {version = ">=2023.1.0,<=2024.2.0", extras = ["http"]} +fsspec = {version = ">=2023.1.0,<=2023.10.0", extras = ["http"]} huggingface-hub = ">=0.19.4" multiprocess = "*" numpy = ">=1.17" @@ -809,11 +785,11 @@ xxhash = "*" apache-beam = ["apache-beam (>=2.26.0)"] audio = ["librosa", "soundfile (>=0.12.1)"] benchmarks = ["tensorflow (==2.12.0)", "torch (==2.0.1)", "transformers (==4.30.1)"] -dev = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "jax (>=0.3.14)", "jaxlib (>=0.3.14)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "ruff (>=0.3.0)", "s3fs", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "torch (>=2.0.0)", "transformers", "typing-extensions (>=4.6.1)", "zstandard"] +dev = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "jax (>=0.3.14)", "jaxlib (>=0.3.14)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "ruff (>=0.1.5)", "s3fs", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "torch (>=2.0.0)", "transformers", "typing-extensions (>=4.6.1)", "zstandard"] docs = ["s3fs", "tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos", "torch", "transformers"] jax = ["jax (>=0.3.14)", "jaxlib (>=0.3.14)"] metrics-tests = ["Werkzeug (>=1.0.1)", "accelerate", "bert-score (>=0.3.6)", "jiwer", "langdetect", "mauve-text", "nltk", "requests-file (>=1.5.1)", "rouge-score", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "six (>=1.15.0,<1.16.0)", "spacy (>=3.0.0)", "texttable (>=1.6.3)", "tldextract", "tldextract (>=3.1.0)", "toml (>=0.10.1)", "typer (<0.5.0)"] -quality = ["ruff (>=0.3.0)"] +quality = ["ruff (>=0.1.5)"] s3 = ["s3fs"] tensorflow = ["tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos"] tensorflow-gpu = ["tensorflow-gpu (>=2.2.0,!=2.6.0,!=2.6.1)"] @@ -895,17 +871,6 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] -[[package]] -name = "distro" -version = "1.9.0" -description = "Distro - an OS platform information API" -optional = true -python-versions = ">=3.6" -files = [ - {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, - {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, -] - [[package]] name = "dnspython" version = "2.6.1" @@ -1034,13 +999,13 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "flatbuffers" -version = "24.3.7" +version = "23.5.26" description = "The FlatBuffers serialization format for Python" optional = true python-versions = "*" files = [ - {file = "flatbuffers-24.3.7-py2.py3-none-any.whl", hash = "sha256:80c4f5dcad0ee76b7e349671a0d657f2fbba927a0244f88dd3f5ed6a3694e1fc"}, - {file = "flatbuffers-24.3.7.tar.gz", hash = "sha256:0895c22b9a6019ff2f4de2e5e2f7cd15914043e6e7033a94c0c6369422690f22"}, + {file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1"}, + {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"}, ] [[package]] @@ -1131,17 +1096,18 @@ files = [ [[package]] name = "fsspec" -version = "2024.2.0" +version = "2023.10.0" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - {file = "fsspec-2024.2.0-py3-none-any.whl", hash = "sha256:817f969556fa5916bc682e02ca2045f96ff7f586d45110fcb76022063ad2c7d8"}, - {file = "fsspec-2024.2.0.tar.gz", hash = "sha256:b6ad1a679f760dda52b1168c859d01b7b80648ea6f7f7c7f5a8a91dc3f3ecb84"}, + {file = "fsspec-2023.10.0-py3-none-any.whl", hash = "sha256:346a8f024efeb749d2a5fca7ba8854474b1ff9af7c3faaf636a4548781136529"}, + {file = "fsspec-2023.10.0.tar.gz", hash = "sha256:330c66757591df346ad3091a53bd907e15348c2ba17d63fd54f5c39c4457d2a5"}, ] [package.dependencies] aiohttp = {version = "<4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1", optional = true, markers = "extra == \"http\""} +requests = {version = "*", optional = true, markers = "extra == \"http\""} [package.extras] abfs = ["adlfs"] @@ -1158,7 +1124,7 @@ github = ["requests"] gs = ["gcsfs"] gui = ["panel"] hdfs = ["pyarrow (>=1)"] -http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"] libarchive = ["libarchive-c"] oci = ["ocifs"] s3 = ["s3fs"] @@ -1203,13 +1169,13 @@ dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "google-auth" -version = "2.28.2" +version = "2.28.1" description = "Google Authentication Library" optional = true python-versions = ">=3.7" files = [ - {file = "google-auth-2.28.2.tar.gz", hash = "sha256:80b8b4969aa9ed5938c7828308f20f035bc79f9d8fb8120bf9dc8db20b41ba30"}, - {file = "google_auth-2.28.2-py2.py3-none-any.whl", hash = "sha256:9fd67bbcd40f16d9d42f950228e9cf02a2ded4ae49198b27432d0cded5a74c38"}, + {file = "google-auth-2.28.1.tar.gz", hash = "sha256:34fc3046c257cedcf1622fc4b31fc2be7923d9b4d44973d481125ecc50d83885"}, + {file = "google_auth-2.28.1-py2.py3-none-any.whl", hash = "sha256:25141e2d7a14bfcba945f5e9827f98092716e99482562f15306e5b026e21aa72"}, ] [package.dependencies] @@ -1314,13 +1280,13 @@ test = ["objgraph", "psutil"] [[package]] name = "griffe" -version = "0.41.3" +version = "0.41.0" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." optional = false python-versions = ">=3.8" files = [ - {file = "griffe-0.41.3-py3-none-any.whl", hash = "sha256:27b4610f1ba6e5d039e9f0a2c97232e13463df75e53cb1833e0679f3377b9de2"}, - {file = "griffe-0.41.3.tar.gz", hash = "sha256:9edcfa9f57f4d9c5fcc6d5ce067c67a685b7101a21a7d11848ce0437368e474c"}, + {file = "griffe-0.41.0-py3-none-any.whl", hash = "sha256:8aa7fc6eb00cb80af9c0198178c6b7110cb59fa2c5187bb13ea25eebbe4dd928"}, + {file = "griffe-0.41.0.tar.gz", hash = "sha256:850128c3198c18713eaf0a6cc8572e590a16b1965f72a4e871e66cf84740903f"}, ] [package.dependencies] @@ -1328,135 +1294,135 @@ colorama = ">=0.4" [[package]] name = "grpcio" -version = "1.62.1" +version = "1.62.0" description = "HTTP/2-based RPC framework" optional = true python-versions = ">=3.7" files = [ - {file = "grpcio-1.62.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:179bee6f5ed7b5f618844f760b6acf7e910988de77a4f75b95bbfaa8106f3c1e"}, - {file = "grpcio-1.62.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:48611e4fa010e823ba2de8fd3f77c1322dd60cb0d180dc6630a7e157b205f7ea"}, - {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:b2a0e71b0a2158aa4bce48be9f8f9eb45cbd17c78c7443616d00abbe2a509f6d"}, - {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbe80577c7880911d3ad65e5ecc997416c98f354efeba2f8d0f9112a67ed65a5"}, - {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f6c693d446964e3292425e1d16e21a97a48ba9172f2d0df9d7b640acb99243"}, - {file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:77c339403db5a20ef4fed02e4d1a9a3d9866bf9c0afc77a42234677313ea22f3"}, - {file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b5a4ea906db7dec694098435d84bf2854fe158eb3cd51e1107e571246d4d1d70"}, - {file = "grpcio-1.62.1-cp310-cp310-win32.whl", hash = "sha256:4187201a53f8561c015bc745b81a1b2d278967b8de35f3399b84b0695e281d5f"}, - {file = "grpcio-1.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:844d1f3fb11bd1ed362d3fdc495d0770cfab75761836193af166fee113421d66"}, - {file = "grpcio-1.62.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:833379943d1728a005e44103f17ecd73d058d37d95783eb8f0b28ddc1f54d7b2"}, - {file = "grpcio-1.62.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:c7fcc6a32e7b7b58f5a7d27530669337a5d587d4066060bcb9dee7a8c833dfb7"}, - {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:fa7d28eb4d50b7cbe75bb8b45ed0da9a1dc5b219a0af59449676a29c2eed9698"}, - {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48f7135c3de2f298b833be8b4ae20cafe37091634e91f61f5a7eb3d61ec6f660"}, - {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f11fd63365ade276c9d4a7b7df5c136f9030e3457107e1791b3737a9b9ed6a"}, - {file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b49fd8fe9f9ac23b78437da94c54aa7e9996fbb220bac024a67469ce5d0825f"}, - {file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:482ae2ae78679ba9ed5752099b32e5fe580443b4f798e1b71df412abf43375db"}, - {file = "grpcio-1.62.1-cp311-cp311-win32.whl", hash = "sha256:1faa02530b6c7426404372515fe5ddf66e199c2ee613f88f025c6f3bd816450c"}, - {file = "grpcio-1.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bd90b8c395f39bc82a5fb32a0173e220e3f401ff697840f4003e15b96d1befc"}, - {file = "grpcio-1.62.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b134d5d71b4e0837fff574c00e49176051a1c532d26c052a1e43231f252d813b"}, - {file = "grpcio-1.62.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d1f6c96573dc09d50dbcbd91dbf71d5cf97640c9427c32584010fbbd4c0e0037"}, - {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:359f821d4578f80f41909b9ee9b76fb249a21035a061a327f91c953493782c31"}, - {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a485f0c2010c696be269184bdb5ae72781344cb4e60db976c59d84dd6354fac9"}, - {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b50b09b4dc01767163d67e1532f948264167cd27f49e9377e3556c3cba1268e1"}, - {file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3227c667dccbe38f2c4d943238b887bac588d97c104815aecc62d2fd976e014b"}, - {file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3952b581eb121324853ce2b191dae08badb75cd493cb4e0243368aa9e61cfd41"}, - {file = "grpcio-1.62.1-cp312-cp312-win32.whl", hash = "sha256:83a17b303425104d6329c10eb34bba186ffa67161e63fa6cdae7776ff76df73f"}, - {file = "grpcio-1.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:6696ffe440333a19d8d128e88d440f91fb92c75a80ce4b44d55800e656a3ef1d"}, - {file = "grpcio-1.62.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:e3393b0823f938253370ebef033c9fd23d27f3eae8eb9a8f6264900c7ea3fb5a"}, - {file = "grpcio-1.62.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:83e7ccb85a74beaeae2634f10eb858a0ed1a63081172649ff4261f929bacfd22"}, - {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:882020c87999d54667a284c7ddf065b359bd00251fcd70279ac486776dbf84ec"}, - {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a10383035e864f386fe096fed5c47d27a2bf7173c56a6e26cffaaa5a361addb1"}, - {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:960edebedc6b9ada1ef58e1c71156f28689978188cd8cff3b646b57288a927d9"}, - {file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:23e2e04b83f347d0aadde0c9b616f4726c3d76db04b438fd3904b289a725267f"}, - {file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978121758711916d34fe57c1f75b79cdfc73952f1481bb9583399331682d36f7"}, - {file = "grpcio-1.62.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9084086190cc6d628f282e5615f987288b95457292e969b9205e45b442276407"}, - {file = "grpcio-1.62.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:22bccdd7b23c420a27fd28540fb5dcbc97dc6be105f7698cb0e7d7a420d0e362"}, - {file = "grpcio-1.62.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:8999bf1b57172dbc7c3e4bb3c732658e918f5c333b2942243f10d0d653953ba9"}, - {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:d9e52558b8b8c2f4ac05ac86344a7417ccdd2b460a59616de49eb6933b07a0bd"}, - {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1714e7bc935780bc3de1b3fcbc7674209adf5208ff825799d579ffd6cd0bd505"}, - {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8842ccbd8c0e253c1f189088228f9b433f7a93b7196b9e5b6f87dba393f5d5d"}, - {file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f1e7b36bdff50103af95a80923bf1853f6823dd62f2d2a2524b66ed74103e49"}, - {file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bba97b8e8883a8038606480d6b6772289f4c907f6ba780fa1f7b7da7dfd76f06"}, - {file = "grpcio-1.62.1-cp38-cp38-win32.whl", hash = "sha256:a7f615270fe534548112a74e790cd9d4f5509d744dd718cd442bf016626c22e4"}, - {file = "grpcio-1.62.1-cp38-cp38-win_amd64.whl", hash = "sha256:e6c8c8693df718c5ecbc7babb12c69a4e3677fd11de8886f05ab22d4e6b1c43b"}, - {file = "grpcio-1.62.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:73db2dc1b201d20ab7083e7041946910bb991e7e9761a0394bbc3c2632326483"}, - {file = "grpcio-1.62.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:407b26b7f7bbd4f4751dbc9767a1f0716f9fe72d3d7e96bb3ccfc4aace07c8de"}, - {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f8de7c8cef9261a2d0a62edf2ccea3d741a523c6b8a6477a340a1f2e417658de"}, - {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd5c8a1af40ec305d001c60236308a67e25419003e9bb3ebfab5695a8d0b369"}, - {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0477cb31da67846a33b1a75c611f88bfbcd427fe17701b6317aefceee1b96f"}, - {file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:60dcd824df166ba266ee0cfaf35a31406cd16ef602b49f5d4dfb21f014b0dedd"}, - {file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:973c49086cabab773525f6077f95e5a993bfc03ba8fc32e32f2c279497780585"}, - {file = "grpcio-1.62.1-cp39-cp39-win32.whl", hash = "sha256:12859468e8918d3bd243d213cd6fd6ab07208195dc140763c00dfe901ce1e1b4"}, - {file = "grpcio-1.62.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7209117bbeebdfa5d898205cc55153a51285757902dd73c47de498ad4d11332"}, - {file = "grpcio-1.62.1.tar.gz", hash = "sha256:6c455e008fa86d9e9a9d85bb76da4277c0d7d9668a3bfa70dbe86e9f3c759947"}, + {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, + {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, + {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, + {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, + {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, + {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, + {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, + {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, + {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, + {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, + {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, + {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, + {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, + {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, + {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, + {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, + {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, + {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, + {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, + {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, + {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, + {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, + {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, + {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, + {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, + {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, + {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, + {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, + {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, + {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, + {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, + {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, + {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, + {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, + {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, + {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.62.1)"] +protobuf = ["grpcio-tools (>=1.62.0)"] [[package]] name = "grpcio-tools" -version = "1.62.1" +version = "1.62.0" description = "Protobuf code generator for gRPC" optional = true python-versions = ">=3.7" files = [ - {file = "grpcio-tools-1.62.1.tar.gz", hash = "sha256:a4991e5ee8a97ab791296d3bf7e8700b1445635cc1828cc98df945ca1802d7f2"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:f2b404bcae7e2ef9b0b9803b2a95119eb7507e6dc80ea4a64a78be052c30cebc"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:fdd987a580b4474769adfd40144486f54bcc73838d5ec5d3647a17883ea78e76"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:07af1a6442e2313cff22af93c2c4dd37ae32b5239b38e0d99e2cbf93de65429f"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41384c9ee18e61ef20cad2774ef71bd8854b63efce263b5177aa06fccb84df1f"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c38006f7702d2ff52122e4c77a47348709374050c76216e84b30a9f06e45afa"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08fecc3c5b4e6dd3278f2b9d12837e423c7dcff551ca1e587018b4a0fc5f8019"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a01e8dcd0f041f6fa6d815c54a2017d032950e310c41d514a8bc041e872c4d12"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-win32.whl", hash = "sha256:dd933b8e0b3c13fe3543d58f849a6a5e0d7987688cb6801834278378c724f695"}, - {file = "grpcio_tools-1.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:2b04844a9382f1bde4b4174e476e654ab3976168d2469cb4b29e352f4f35a5aa"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:024380536ba71a96cdf736f0954f6ad03f5da609c09edbcc2ca02fdd639e0eed"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:21f14b99e0cd38ad56754cc0b62b2bf3cf75f9f7fc40647da54669e0da0726fe"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:975ac5fb482c23f3608c16e06a43c8bab4d79c2e2564cdbc25cf753c6e998775"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50739aaab0c8076ad5957204e71f2e0c9876e11fd8338f7f09de12c2d75163c5"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598c54318f0326cf5020aa43fc95a15e933aba4a71943d3bff2677d2d21ddfa1"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f309bdb33a61f8e049480d41498ee2e525cfb5e959958b326abfdf552bf9b9cb"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f358effd3c11d66c150e0227f983d54a5cd30e14038566dadcf25f9f6844e6e8"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-win32.whl", hash = "sha256:b76aead9b73f1650a091870fe4e9ed15ac4d8ed136f962042367255199c23594"}, - {file = "grpcio_tools-1.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:d66a5d47eaa427039752fa0a83a425ff2a487b6a0ac30556fd3be2f3a27a0130"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:575535d039b97d63e6a9abee626d6c7cd47bd8cb73dd00a5c84a98254a2164a4"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:22644c90e43d1a888477899af917979e17364fdd6e9bbb92679cd6a54c4d36c3"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:156d3e1b227c16e903003a56881dbe60e40f2b4bd66f0bc3b27c53e466e6384d"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ad7c5691625a85327e5b683443baf73ae790fd5afc938252041ed5cd665e377"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e140bbc08eea8abf51c0274f45fb1e8350220e64758998d7f3c7f985a0b2496"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7444fcab861911525470d398e5638b70d5cbea3b4674a3de92b5c58c5c515d4d"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e643cd14a5d1e59865cba68a5a6f0175d987f36c5f4cb0db80dee9ed60b4c174"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-win32.whl", hash = "sha256:1344a773d2caa9bb7fbea7e879b84f33740c808c34a5bd2a2768e526117a6b44"}, - {file = "grpcio_tools-1.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:2eea1db3748b2f37b4dce84d8e0c15d9bc811094807cabafe7b0ea47f424dfd5"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:45d2e6cf04d27286b6f73e6e20ba3f0a1f6d8f5535e5dcb1356200419bb457f4"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:46ae58e6926773e7315e9005f0f17aacedbc0895a8752bec087d24efa2f1fb21"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:4c28086df31478023a36f45e50767872ab3aed2419afff09814cb61c88b77db4"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4fba5b339f4797548591036c9481e6895bf920fab7d3dc664d2697f8fb7c0bf"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23eb3d47f78f509fcd201749b1f1e44b76f447913f7fbb3b8bae20f109086295"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fd5d47707bd6bc2b707ece765c362d2a1d2e8f6cd92b04c99fab49a929f3610c"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d1924a6a943df7c73b9ef0048302327c75962b567451479710da729ead241228"}, - {file = "grpcio_tools-1.62.1-cp37-cp37m-win_amd64.whl", hash = "sha256:fe71ca30aabe42591e84ecb9694c0297dc699cc20c5b24d2cb267fb0fc01f947"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:1819fd055c1ae672d1d725ec75eefd1f700c18acba0ed9332202be31d69c401d"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:5dbe1f7481dd14b6d477b4bace96d275090bc7636b9883975a08b802c94e7b78"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:771c051c5ece27ad03e4f2e33624a925f0ad636c01757ab7dbb04a37964af4ba"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98209c438b38b6f1276dbc27b1c04e346a75bfaafe72a25a548f2dc5ce71d226"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2152308e5321cb90fb45aaa84d03d6dedb19735a8779aaf36c624f97b831842d"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ed1f27dc2b2262c8b8d9036276619c1bb18791311c16ccbf1f31b660f2aad7cf"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2744947b6c5e907af21133431809ccca535a037356864e32c122efed8cb9de1f"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-win32.whl", hash = "sha256:13b20e269d14ad629ff9a2c9a2450f3dbb119d5948de63b27ffe624fa7aea85a"}, - {file = "grpcio_tools-1.62.1-cp38-cp38-win_amd64.whl", hash = "sha256:999823758e9eacd0095863d06cd6d388be769f80c9abb65cdb11c4f2cfce3fea"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:941f8a5c31986053e75fa466bcfa743c2bf1b513b7978cf1f4ab4e96a8219d27"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b9c02c88c77ef6057c6cbeea8922d7c2424aabf46bfc40ddf42a32765ba91061"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:6abd4eb3ccb444383a40156139acc3aaa73745d395139cb6bc8e2a3429e1e627"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:449503213d142f8470b331a1c2f346f8457f16c7fe20f531bc2500e271f7c14c"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a11bcf609d00cfc9baed77ab308223cabc1f0b22a05774a26dd4c94c0c80f1f"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5d7bdea33354b55acf40bb4dd3ba7324d6f1ef6b4a1a4da0807591f8c7e87b9a"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d03b645852d605f43003020e78fe6d573cae6ee6b944193e36b8b317e7549a20"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-win32.whl", hash = "sha256:52b185dfc3bf32e70929310367dbc66185afba60492a6a75a9b1141d407e160c"}, - {file = "grpcio_tools-1.62.1-cp39-cp39-win_amd64.whl", hash = "sha256:63a273b70896d3640b7a883eb4a080c3c263d91662d870a2e9c84b7bbd978e7b"}, + {file = "grpcio-tools-1.62.0.tar.gz", hash = "sha256:7fca6ecfbbf0549058bb29dcc6e435d885b878d07701e77ac58e1e1f591736dc"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:465c51ebaa184ee3bb619cd5bfaf562bbdde166f2822a6935461e6a741f5ac19"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:0d9c9a4832f52c4597d6dc12d9ab3109c3bd0ee1686b8bf6d64f9eab4145e3cb"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:5a482d9625209023481e631c29a6df1392bfc49f9accfa880dabbacff642559a"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74196beed18383d53ff3e2412a6c1eefa3ff109e987be240368496bc3dcabc8b"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aca28cbeb605c59b5689a7e000fbc2bd659d2f322c58461f3912f00069f6da"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:523adf731fa4c5af0bf7ee2edb65e8c7ef4d9df9951461d6a18fe096688efd2d"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:791aa220f8f1936e65bc079e9eb954fa0202a1f16e28b83956e59d17dface127"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-win32.whl", hash = "sha256:5dacc691b18d2c294ea971720ff980a1e2d68a3f7ddcd2f0670b3204e81c4b18"}, + {file = "grpcio_tools-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:6999a4e705b03aacad46e625feb7610e47ec88dbd51220c2282b6334f90721fc"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:19b74e141937c885c9e56b6a7dfa190ca7d583bd48bce9171dd65bbf108b9271"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:17c16e9a89c0b9f4ff2b143f232c5256383453ce7b55fe981598f9517adc8252"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:3730b1cd998a0cffc817602cc55e51f268fa97b3e38fa4bee578e3741474547a"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14201950513636f515dd455a06890e3a21d115b943cf6a8f5af67ad1413cfa1f"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f74e0053360e0eadd75193c0c379b6d7f51d074ebbff856bd41780e1a028b38d"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d5959e3df126931d28cd94dd5f0a708b7dd96019de80ab715fb922fd0c8a838d"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1927934dfba4658a97c2dab267e53ed239264d40fdd5b295fc317693543db85b"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-win32.whl", hash = "sha256:2f5bd22203e64e1732e149bfdd3083716d038abca294e4e2852159b3d893f9ec"}, + {file = "grpcio_tools-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:cd1f4caeca614b04db803566473f7db0971e7a88268f95e4a529b0ace699b949"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f0884eaf6a2bbd7b03fea456e808909ee48dd4f7f455519d67defda791116368"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:6b900ae319b6f9ac1be0ca572dfb41c23a7ff6fcbf36e3be6d3054e1e4c60de6"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:3bbe79b134dfb7c98cf60e4962e31039bef824834cc7034bdf1886a2ed1097f9"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77196c7ac8741d4a2aebb023bcc2964ac65ca44180fd791640889ab2afed3e47"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b65288ebe12e38dd3650fea65d82fcce0d35df1ae4a770b525c10119ee71962f"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52b216c458458f6c292e12428916e80974c5113abc505a61e7b0b9f8932a785d"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88aa62303278aec45bbb26bf679269c7890346c37140ae30e39da1070c341e11"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-win32.whl", hash = "sha256:bb6802d63e42734d2baf02e1343377fe18590ed6a1f5ffbdebbbe0f8331f176b"}, + {file = "grpcio_tools-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:d5652d3a52a2e8e1d9bdf28fbd15e21b166e31b968cd7c8c604bf31611c0bb5b"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:84e27206bd884be83a7fdcef8be3c90eb1591341c0ba9b0d25ec9db1043ba2f2"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:5eb63d9207b02a0fa30216907e1e7705cc2670f933e77236c6e0eb966ad3b4bf"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:95e49839d49e79187c43cd63af5c206dc5743a01d7d3d2f039772fa743cbb30c"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ae5cd2f89e33a529790bf8aa59a459484edb05e4f58d4cf78836b9dfa1fab43"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e1fd7301d762bf5984b7e7fb62fce82cff864d75f0a57e15cfd07ae1bd79133"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e38d5800151e6804d500e329f7ddfb615c50eee0c1607593e3147a4b21037e40"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:563a75924109e75809b2919e68d7e6ae7872e63d20258aae7899b14f6ff9e18b"}, + {file = "grpcio_tools-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8934715577c9cc0c792b8a77f7d0dd2bb60e951161b10c5f46b60856673240"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:ed6cf7ff4a10c46f85340f9c68982f9efb29f51ee4b66828310fcdf3c2d7ffd1"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:1faa5006fe9e7b9e65c47bc23f7cd333fdcdd4ba35d44080303848266db5ab05"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:3b526dc5566161a3a17599753838b9cfbdd4cb15b6ad419aae8a5d12053fa8ae"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09db3688efd3499ce3c0b02c0bac0656abdab4cb99716f81ad879c08b92c56e"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:006ea0cc16e8bf8f307326e0556e1384f24abb402cc4e6a720aa1dfe8f268647"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b46ba0b6552b4375ede65e0c89491af532635347f78d52a72f8a027529e713ed"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ec6f561c86fe13cff3be16f297cc05e1aa1274294524743a4cf91d971866fbb0"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-win32.whl", hash = "sha256:c85391e06620d6e16a56341caae5007d0c6219beba065e1e288f2523fba6a335"}, + {file = "grpcio_tools-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:679cf2507090e010da73e5001665c76de2a5927b2e2110e459222b1c81cb10c2"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:0e87f105f1d152934759f8975ed002d5ce057b3cdf1cc6cb63fe6008671a27b9"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:bf9f281f528e0220558d57e09b4518dec148dcb250d78bd9cbb27e09edabb3f9"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:711314cb4c6c8b3d51bafaee380ffa5012bd0567ed68f1b0b1fc07492b27acab"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54bb570bd963905de3bda596b35e06026552705edebbb2cb737b57aa5252b9e5"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dce5f04676cf94e6e2d13d7f91ac2de79097d86675bc4d404a3c24dcc0332c88"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:98ddf871c614cc0ed331c7159ebbbf5040be562279677d3bb97c2e6083539f72"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f3aaf3b20c0f7063856b2432335af8f76cf580f898e04085548cde28332d6833"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-win32.whl", hash = "sha256:3dee3be61d9032f777a9b4e2696ea3d0748a582cb99c672b5d41ca66821e8c87"}, + {file = "grpcio_tools-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:f54b5181784464bd3573ae7dbcf053da18a4b7a75fe19960791f383be3d035ca"}, ] [package.dependencies] -grpcio = ">=1.62.1" +grpcio = ">=1.62.0" protobuf = ">=4.21.6,<5.0dev" setuptools = "*" @@ -1593,13 +1559,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" -version = "0.21.4" +version = "0.20.3" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.21.4-py3-none-any.whl", hash = "sha256:df37c2c37fc6c82163cdd8a67ede261687d80d1e262526d6c0ce73b6b3630a7b"}, - {file = "huggingface_hub-0.21.4.tar.gz", hash = "sha256:e1f4968c93726565a80edf6dc309763c7b546d0cfe79aa221206034d50155531"}, + {file = "huggingface_hub-0.20.3-py3-none-any.whl", hash = "sha256:d988ae4f00d3e307b0c80c6a05ca6dbb7edba8bba3079f74cda7d9c2e562a7b6"}, + {file = "huggingface_hub-0.20.3.tar.gz", hash = "sha256:94e7f8e074475fbc67d6a71957b678e1b4a74ff1b64a644fd6cbb83da962d05d"}, ] [package.dependencies] @@ -1616,12 +1582,11 @@ all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", cli = ["InquirerPy (==0.3.4)"] dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "mypy (==1.5.1)", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.1.3)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] -hf-transfer = ["hf-transfer (>=0.1.4)"] inference = ["aiohttp", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)"] quality = ["mypy (==1.5.1)", "ruff (>=0.1.3)"] tensorflow = ["graphviz", "pydot", "tensorflow"] testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic (>1.1,<2.0)", "pydantic (>1.1,<3.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] -torch = ["safetensors", "torch"] +torch = ["torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] [[package]] @@ -1673,32 +1638,32 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.2" +version = "7.0.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"}, - {file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +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 = "importlib-resources" -version = "6.1.3" +version = "6.1.2" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.3-py3-none-any.whl", hash = "sha256:4c0269e3580fe2634d364b39b38b961540a7738c02cb984e98add8b4221d793d"}, - {file = "importlib_resources-6.1.3.tar.gz", hash = "sha256:56fb4525197b78544a3354ea27793952ab93f935bb4bf746b846bb1015020f2b"}, + {file = "importlib_resources-6.1.2-py3-none-any.whl", hash = "sha256:9a0a862501dc38b68adebc82970140c9e4209fc99601782925178f8386339938"}, + {file = "importlib_resources-6.1.2.tar.gz", hash = "sha256:308abf8474e2dba5f867d279237cd4076482c3de7104a40b41426370e891549b"}, ] [package.dependencies] @@ -1706,7 +1671,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.collections", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -1721,13 +1686,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.29.3" +version = "6.29.2" description = "IPython Kernel for Jupyter" optional = true python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.3-py3-none-any.whl", hash = "sha256:5aa086a4175b0229d4eca211e181fb473ea78ffd9869af36ba7694c947302a21"}, - {file = "ipykernel-6.29.3.tar.gz", hash = "sha256:e14c250d1f9ea3989490225cc1a542781b095a18a19447fcf2b5eaf7d0ac5bd2"}, + {file = "ipykernel-6.29.2-py3-none-any.whl", hash = "sha256:50384f5c577a260a1d53f1f59a828c7266d321c9b7d00d345693783f66616055"}, + {file = "ipykernel-6.29.2.tar.gz", hash = "sha256:3bade28004e3ff624ed57974948116670604ac5f676d12339693f3142176d3f0"}, ] [package.dependencies] @@ -1750,7 +1715,7 @@ cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] pyqt5 = ["pyqt5"] pyside6 = ["pyside6"] -test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (==0.23.4)", "pytest-cov", "pytest-timeout"] [[package]] name = "ipython" @@ -2284,18 +2249,17 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp [[package]] name = "mkdocs-autorefs" -version = "1.0.1" +version = "0.5.0" description = "Automatically link across pages in MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_autorefs-1.0.1-py3-none-any.whl", hash = "sha256:aacdfae1ab197780fb7a2dac92ad8a3d8f7ca8049a9cbe56a4218cd52e8da570"}, - {file = "mkdocs_autorefs-1.0.1.tar.gz", hash = "sha256:f684edf847eced40b570b57846b15f0bf57fb93ac2c510450775dcf16accb971"}, + {file = "mkdocs_autorefs-0.5.0-py3-none-any.whl", hash = "sha256:7930fcb8ac1249f10e683967aeaddc0af49d90702af111a5e390e8b20b3d97ff"}, + {file = "mkdocs_autorefs-0.5.0.tar.gz", hash = "sha256:9a5054a94c08d28855cfab967ada10ed5be76e2bfad642302a610b252c3274c0"}, ] [package.dependencies] Markdown = ">=3.3" -markupsafe = ">=2.0.1" mkdocs = ">=1.1" [[package]] @@ -2314,13 +2278,13 @@ mkdocs = ">=1.0.3" [[package]] name = "mkdocs-material" -version = "9.5.13" +version = "9.5.11" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.13-py3-none-any.whl", hash = "sha256:5cbe17fee4e3b4980c8420a04cc762d8dc052ef1e10532abd4fce88e5ea9ce6a"}, - {file = "mkdocs_material-9.5.13.tar.gz", hash = "sha256:d8e4caae576312a88fd2609b81cf43d233cdbe36860d67a68702b018b425bd87"}, + {file = "mkdocs_material-9.5.11-py3-none-any.whl", hash = "sha256:788ee0f3e036dca2dc20298d65e480297d348a44c9d7b2ee05c5262983e66072"}, + {file = "mkdocs_material-9.5.11.tar.gz", hash = "sha256:7af7f8af0dea16175558f3fb9245d26c83a17199baa5f157755e63d7437bf971"}, ] [package.dependencies] @@ -2354,13 +2318,13 @@ files = [ [[package]] name = "mkdocstrings" -version = "0.24.1" +version = "0.24.0" description = "Automatic documentation from sources, for MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings-0.24.1-py3-none-any.whl", hash = "sha256:b4206f9a2ca8a648e222d5a0ca1d36ba7dee53c88732818de183b536f9042b5d"}, - {file = "mkdocstrings-0.24.1.tar.gz", hash = "sha256:cc83f9a1c8724fc1be3c2fa071dd73d91ce902ef6a79710249ec8d0ee1064401"}, + {file = "mkdocstrings-0.24.0-py3-none-any.whl", hash = "sha256:f4908560c10f587326d8f5165d1908817b2e280bbf707607f601c996366a2264"}, + {file = "mkdocstrings-0.24.0.tar.gz", hash = "sha256:222b1165be41257b494a9d29b14135d2b7ca43f38161d5b10caae03b87bd4f7e"}, ] [package.dependencies] @@ -3148,13 +3112,13 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p [[package]] name = "posthog" -version = "3.5.0" +version = "3.4.2" description = "Integrate PostHog into any python application." optional = true python-versions = "*" files = [ - {file = "posthog-3.5.0-py2.py3-none-any.whl", hash = "sha256:3c672be7ba6f95d555ea207d4486c171d06657eb34b3ce25eb043bfe7b6b5b76"}, - {file = "posthog-3.5.0.tar.gz", hash = "sha256:8f7e3b2c6e8714d0c0c542a2109b83a7549f63b7113a133ab2763a89245ef2ef"}, + {file = "posthog-3.4.2-py2.py3-none-any.whl", hash = "sha256:c7e79b2e585d16e93749874bcbcdad78d857037398ce0d8d6c474a04d0bd3bbe"}, + {file = "posthog-3.4.2.tar.gz", hash = "sha256:f0eafa663fbc4a942b49b6168a62a890635407044bbc7593051dcb9cc1208873"}, ] [package.dependencies] @@ -3316,47 +3280,47 @@ files = [ [[package]] name = "pyarrow" -version = "15.0.1" +version = "15.0.0" description = "Python library for Apache Arrow" optional = false python-versions = ">=3.8" files = [ - {file = "pyarrow-15.0.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:c2ddb3be5ea938c329a84171694fc230b241ce1b6b0ff1a0280509af51c375fa"}, - {file = "pyarrow-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7543ea88a0ff72f8e6baaf9bfdbec2c62aeabdbede9e4a571c71cc3bc43b6302"}, - {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1519e218a6941fc074e4501088d891afcb2adf77c236e03c34babcf3d6a0d1c7"}, - {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28cafa86e1944761970d3b3fc0411b14ff9b5c2b73cd22aaf470d7a3976335f5"}, - {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:be5c3d463e33d03eab496e1af7916b1d44001c08f0f458ad27dc16093a020638"}, - {file = "pyarrow-15.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:47b1eda15d3aa3f49a07b1808648e1397e5dc6a80a30bf87faa8e2d02dad7ac3"}, - {file = "pyarrow-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e524a31be7db22deebbbcf242b189063ab9a7652c62471d296b31bc6e3cae77b"}, - {file = "pyarrow-15.0.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:a476fefe8bdd56122fb0d4881b785413e025858803cc1302d0d788d3522b374d"}, - {file = "pyarrow-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:309e6191be385f2e220586bfdb643f9bb21d7e1bc6dd0a6963dc538e347b2431"}, - {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83bc586903dbeb4365cbc72b602f99f70b96c5882e5dfac5278813c7d624ca3c"}, - {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e652daac6d8b05280cd2af31c0fb61a4490ec6a53dc01588014d9fa3fdbee9"}, - {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:abad2e08652df153a72177ce20c897d083b0c4ebeec051239e2654ddf4d3c996"}, - {file = "pyarrow-15.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cde663352bc83ad75ba7b3206e049ca1a69809223942362a8649e37bd22f9e3b"}, - {file = "pyarrow-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1b6e237dd7a08482a8b8f3f6512d258d2460f182931832a8c6ef3953203d31e1"}, - {file = "pyarrow-15.0.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:7bd167536ee23192760b8c731d39b7cfd37914c27fd4582335ffd08450ff799d"}, - {file = "pyarrow-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7c08bb31eb2984ba5c3747d375bb522e7e536b8b25b149c9cb5e1c49b0ccb736"}, - {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0f9c1d630ed2524bd1ddf28ec92780a7b599fd54704cd653519f7ff5aec177a"}, - {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5186048493395220550bca7b524420471aac2d77af831f584ce132680f55c3df"}, - {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:31dc30c7ec8958da3a3d9f31d6c3630429b2091ede0ecd0d989fd6bec129f0e4"}, - {file = "pyarrow-15.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3f111a014fb8ac2297b43a74bf4495cc479a332908f7ee49cb7cbd50714cb0c1"}, - {file = "pyarrow-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a6d1f7c15d7f68f08490d0cb34611497c74285b8a6bbeab4ef3fc20117310983"}, - {file = "pyarrow-15.0.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:9ad931b996f51c2f978ed517b55cb3c6078272fb4ec579e3da5a8c14873b698d"}, - {file = "pyarrow-15.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:738f6b53ab1c2f66b2bde8a1d77e186aeaab702d849e0dfa1158c9e2c030add3"}, - {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c1c3fc16bc74e33bf8f1e5a212938ed8d88e902f372c4dac6b5bad328567d2f"}, - {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1fa92512128f6c1b8dde0468c1454dd70f3bff623970e370d52efd4d24fd0be"}, - {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:b4157f307c202cbbdac147d9b07447a281fa8e63494f7fc85081da351ec6ace9"}, - {file = "pyarrow-15.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:b75e7da26f383787f80ad76143b44844ffa28648fcc7099a83df1538c078d2f2"}, - {file = "pyarrow-15.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:3a99eac76ae14096c209850935057b9e8ce97a78397c5cde8724674774f34e5d"}, - {file = "pyarrow-15.0.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:dd532d3177e031e9b2d2df19fd003d0cc0520d1747659fcabbd4d9bb87de508c"}, - {file = "pyarrow-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ce8c89848fd37e5313fc2ce601483038ee5566db96ba0808d5883b2e2e55dc53"}, - {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:862eac5e5f3b6477f7a92b2f27e560e1f4e5e9edfca9ea9da8a7478bb4abd5ce"}, - {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f0ea3a29cd5cb99bf14c1c4533eceaa00ea8fb580950fb5a89a5c771a994a4e"}, - {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:bb902f780cfd624b2e8fd8501fadab17618fdb548532620ef3d91312aaf0888a"}, - {file = "pyarrow-15.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:4f87757f02735a6bb4ad2e1b98279ac45d53b748d5baf52401516413007c6999"}, - {file = "pyarrow-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:efd3816c7fbfcbd406ac0f69873cebb052effd7cdc153ae5836d1b00845845d7"}, - {file = "pyarrow-15.0.1.tar.gz", hash = "sha256:21d812548d39d490e0c6928a7c663f37b96bf764034123d4b4ab4530ecc757a9"}, + {file = "pyarrow-15.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0a524532fd6dd482edaa563b686d754c70417c2f72742a8c990b322d4c03a15d"}, + {file = "pyarrow-15.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:60a6bdb314affa9c2e0d5dddf3d9cbb9ef4a8dddaa68669975287d47ece67642"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66958fd1771a4d4b754cd385835e66a3ef6b12611e001d4e5edfcef5f30391e2"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f500956a49aadd907eaa21d4fff75f73954605eaa41f61cb94fb008cf2e00c6"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6f87d9c4f09e049c2cade559643424da84c43a35068f2a1c4653dc5b1408a929"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85239b9f93278e130d86c0e6bb455dcb66fc3fd891398b9d45ace8799a871a1e"}, + {file = "pyarrow-15.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b8d43e31ca16aa6e12402fcb1e14352d0d809de70edd185c7650fe80e0769e3"}, + {file = "pyarrow-15.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:fa7cd198280dbd0c988df525e50e35b5d16873e2cdae2aaaa6363cdb64e3eec5"}, + {file = "pyarrow-15.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8780b1a29d3c8b21ba6b191305a2a607de2e30dab399776ff0aa09131e266340"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0ec198ccc680f6c92723fadcb97b74f07c45ff3fdec9dd765deb04955ccf19"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036a7209c235588c2f07477fe75c07e6caced9b7b61bb897c8d4e52c4b5f9555"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bd8a0e5296797faf9a3294e9fa2dc67aa7f10ae2207920dbebb785c77e9dbe5"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e8ebed6053dbe76883a822d4e8da36860f479d55a762bd9e70d8494aed87113e"}, + {file = "pyarrow-15.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d53a9d1b2b5bd7d5e4cd84d018e2a45bc9baaa68f7e6e3ebed45649900ba99"}, + {file = "pyarrow-15.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9950a9c9df24090d3d558b43b97753b8f5867fb8e521f29876aa021c52fda351"}, + {file = "pyarrow-15.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:003d680b5e422d0204e7287bb3fa775b332b3fce2996aa69e9adea23f5c8f970"}, + {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f75fce89dad10c95f4bf590b765e3ae98bcc5ba9f6ce75adb828a334e26a3d40"}, + {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca9cb0039923bec49b4fe23803807e4ef39576a2bec59c32b11296464623dc2"}, + {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ed5a78ed29d171d0acc26a305a4b7f83c122d54ff5270810ac23c75813585e4"}, + {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6eda9e117f0402dfcd3cd6ec9bfee89ac5071c48fc83a84f3075b60efa96747f"}, + {file = "pyarrow-15.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a3a6180c0e8f2727e6f1b1c87c72d3254cac909e609f35f22532e4115461177"}, + {file = "pyarrow-15.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:19a8918045993349b207de72d4576af0191beef03ea655d8bdb13762f0cd6eac"}, + {file = "pyarrow-15.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0ec076b32bacb6666e8813a22e6e5a7ef1314c8069d4ff345efa6246bc38593"}, + {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5db1769e5d0a77eb92344c7382d6543bea1164cca3704f84aa44e26c67e320fb"}, + {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2617e3bf9df2a00020dd1c1c6dce5cc343d979efe10bc401c0632b0eef6ef5b"}, + {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:d31c1d45060180131caf10f0f698e3a782db333a422038bf7fe01dace18b3a31"}, + {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:c8c287d1d479de8269398b34282e206844abb3208224dbdd7166d580804674b7"}, + {file = "pyarrow-15.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:07eb7f07dc9ecbb8dace0f58f009d3a29ee58682fcdc91337dfeb51ea618a75b"}, + {file = "pyarrow-15.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:47af7036f64fce990bb8a5948c04722e4e3ea3e13b1007ef52dfe0aa8f23cf7f"}, + {file = "pyarrow-15.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93768ccfff85cf044c418bfeeafce9a8bb0cee091bd8fd19011aff91e58de540"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ee87fd6892700960d90abb7b17a72a5abb3b64ee0fe8db6c782bcc2d0dc0b4"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:001fca027738c5f6be0b7a3159cc7ba16a5c52486db18160909a0831b063c4e4"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:d1c48648f64aec09accf44140dccb92f4f94394b8d79976c426a5b79b11d4fa7"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:972a0141be402bb18e3201448c8ae62958c9c7923dfaa3b3d4530c835ac81aed"}, + {file = "pyarrow-15.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:f01fc5cf49081426429127aa2d427d9d98e1cb94a32cb961d583a70b7c4504e6"}, + {file = "pyarrow-15.0.0.tar.gz", hash = "sha256:876858f549d540898f927eba4ef77cd549ad8d24baa3207cf1b72e5788b50e83"}, ] [package.dependencies] @@ -3577,13 +3541,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.7.1" +version = "10.7" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.7.1-py3-none-any.whl", hash = "sha256:f5cc7000d7ff0d1ce9395d216017fa4df3dde800afb1fb72d1c7d3fd35e710f4"}, - {file = "pymdown_extensions-10.7.1.tar.gz", hash = "sha256:c70e146bdd83c744ffc766b4671999796aba18842b268510a329f7f64700d584"}, + {file = "pymdown_extensions-10.7-py3-none-any.whl", hash = "sha256:6ca215bc57bc12bf32b414887a68b810637d039124ed9b2e5bd3325cbb2c050c"}, + {file = "pymdown_extensions-10.7.tar.gz", hash = "sha256:c0d64d5cf62566f59e6b2b690a4095c931107c250a8c8e1351c1de5f6b036deb"}, ] [package.dependencies] @@ -3595,13 +3559,13 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pyparsing" -version = "3.1.2" +version = "3.1.1" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, - {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, ] [package.extras] @@ -3654,13 +3618,13 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "python-dateutil" -version = "2.9.0.post0" +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.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, + {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] @@ -3895,13 +3859,13 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "qdrant-client" -version = "1.8.0" +version = "1.7.3" description = "Client library for the Qdrant vector search engine" optional = true python-versions = ">=3.8" files = [ - {file = "qdrant_client-1.8.0-py3-none-any.whl", hash = "sha256:fa28d3eb64c0c57ec029c7c85c71f6c72c197f92502022655741f3632c518e29"}, - {file = "qdrant_client-1.8.0.tar.gz", hash = "sha256:2a1a3f2cbacc7adba85644cf6cfdee20401cf25764b32da479c81fb63e178d15"}, + {file = "qdrant_client-1.7.3-py3-none-any.whl", hash = "sha256:b062420ba55eb847652c7d2a26404fb1986bea13aa785763024013f96a7a915c"}, + {file = "qdrant_client-1.7.3.tar.gz", hash = "sha256:7b809be892cdc5137ae80ea3335da40c06499ad0b0072b5abc6bad79da1d29fc"}, ] [package.dependencies] @@ -3914,7 +3878,7 @@ pydantic = ">=1.10.8" urllib3 = ">=1.26.14,<3" [package.extras] -fastembed = ["fastembed (==0.2.2)"] +fastembed = ["fastembed (==0.1.1)"] [[package]] name = "referencing" @@ -4486,60 +4450,60 @@ test = ["pytest"] [[package]] name = "sqlalchemy" -version = "2.0.28" +version = "2.0.27" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0b148ab0438f72ad21cb004ce3bdaafd28465c4276af66df3b9ecd2037bf252"}, - {file = "SQLAlchemy-2.0.28-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbda76961eb8f27e6ad3c84d1dc56d5bc61ba8f02bd20fcf3450bd421c2fcc9c"}, - {file = "SQLAlchemy-2.0.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feea693c452d85ea0015ebe3bb9cd15b6f49acc1a31c28b3c50f4db0f8fb1e71"}, - {file = "SQLAlchemy-2.0.28-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5da98815f82dce0cb31fd1e873a0cb30934971d15b74e0d78cf21f9e1b05953f"}, - {file = "SQLAlchemy-2.0.28-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a5adf383c73f2d49ad15ff363a8748319ff84c371eed59ffd0127355d6ea1da"}, - {file = "SQLAlchemy-2.0.28-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56856b871146bfead25fbcaed098269d90b744eea5cb32a952df00d542cdd368"}, - {file = "SQLAlchemy-2.0.28-cp310-cp310-win32.whl", hash = "sha256:943aa74a11f5806ab68278284a4ddd282d3fb348a0e96db9b42cb81bf731acdc"}, - {file = "SQLAlchemy-2.0.28-cp310-cp310-win_amd64.whl", hash = "sha256:c6c4da4843e0dabde41b8f2e8147438330924114f541949e6318358a56d1875a"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46a3d4e7a472bfff2d28db838669fc437964e8af8df8ee1e4548e92710929adc"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3dd67b5d69794cfe82862c002512683b3db038b99002171f624712fa71aeaa"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61e2e41656a673b777e2f0cbbe545323dbe0d32312f590b1bc09da1de6c2a02"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0315d9125a38026227f559488fe7f7cee1bd2fbc19f9fd637739dc50bb6380b2"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af8ce2d31679006e7b747d30a89cd3ac1ec304c3d4c20973f0f4ad58e2d1c4c9"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:81ba314a08c7ab701e621b7ad079c0c933c58cdef88593c59b90b996e8b58fa5"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-win32.whl", hash = "sha256:1ee8bd6d68578e517943f5ebff3afbd93fc65f7ef8f23becab9fa8fb315afb1d"}, - {file = "SQLAlchemy-2.0.28-cp311-cp311-win_amd64.whl", hash = "sha256:ad7acbe95bac70e4e687a4dc9ae3f7a2f467aa6597049eeb6d4a662ecd990bb6"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d3499008ddec83127ab286c6f6ec82a34f39c9817f020f75eca96155f9765097"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9b66fcd38659cab5d29e8de5409cdf91e9986817703e1078b2fdaad731ea66f5"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea30da1e76cb1acc5b72e204a920a3a7678d9d52f688f087dc08e54e2754c67"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:124202b4e0edea7f08a4db8c81cc7859012f90a0d14ba2bf07c099aff6e96462"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e23b88c69497a6322b5796c0781400692eca1ae5532821b39ce81a48c395aae9"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b6303bfd78fb3221847723104d152e5972c22367ff66edf09120fcde5ddc2e2"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-win32.whl", hash = "sha256:a921002be69ac3ab2cf0c3017c4e6a3377f800f1fca7f254c13b5f1a2f10022c"}, - {file = "SQLAlchemy-2.0.28-cp312-cp312-win_amd64.whl", hash = "sha256:b4a2cf92995635b64876dc141af0ef089c6eea7e05898d8d8865e71a326c0385"}, - {file = "SQLAlchemy-2.0.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e91b5e341f8c7f1e5020db8e5602f3ed045a29f8e27f7f565e0bdee3338f2c7"}, - {file = "SQLAlchemy-2.0.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c7b78dfc7278329f27be02c44abc0d69fe235495bb8e16ec7ef1b1a17952db"}, - {file = "SQLAlchemy-2.0.28-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eba73ef2c30695cb7eabcdb33bb3d0b878595737479e152468f3ba97a9c22a4"}, - {file = "SQLAlchemy-2.0.28-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5df5d1dafb8eee89384fb7a1f79128118bc0ba50ce0db27a40750f6f91aa99d5"}, - {file = "SQLAlchemy-2.0.28-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2858bbab1681ee5406650202950dc8f00e83b06a198741b7c656e63818633526"}, - {file = "SQLAlchemy-2.0.28-cp37-cp37m-win32.whl", hash = "sha256:9461802f2e965de5cff80c5a13bc945abea7edaa1d29360b485c3d2b56cdb075"}, - {file = "SQLAlchemy-2.0.28-cp37-cp37m-win_amd64.whl", hash = "sha256:a6bec1c010a6d65b3ed88c863d56b9ea5eeefdf62b5e39cafd08c65f5ce5198b"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:843a882cadebecc655a68bd9a5b8aa39b3c52f4a9a5572a3036fb1bb2ccdc197"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dbb990612c36163c6072723523d2be7c3eb1517bbdd63fe50449f56afafd1133"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7e4baf9161d076b9a7e432fce06217b9bd90cfb8f1d543d6e8c4595627edb9"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0a5354cb4de9b64bccb6ea33162cb83e03dbefa0d892db88a672f5aad638a75"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fffcc8edc508801ed2e6a4e7b0d150a62196fd28b4e16ab9f65192e8186102b6"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aca7b6d99a4541b2ebab4494f6c8c2f947e0df4ac859ced575238e1d6ca5716b"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-win32.whl", hash = "sha256:8c7f10720fc34d14abad5b647bc8202202f4948498927d9f1b4df0fb1cf391b7"}, - {file = "SQLAlchemy-2.0.28-cp38-cp38-win_amd64.whl", hash = "sha256:243feb6882b06a2af68ecf4bec8813d99452a1b62ba2be917ce6283852cf701b"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc4974d3684f28b61b9a90fcb4c41fb340fd4b6a50c04365704a4da5a9603b05"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87724e7ed2a936fdda2c05dbd99d395c91ea3c96f029a033a4a20e008dd876bf"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68722e6a550f5de2e3cfe9da6afb9a7dd15ef7032afa5651b0f0c6b3adb8815d"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:328529f7c7f90adcd65aed06a161851f83f475c2f664a898af574893f55d9e53"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:df40c16a7e8be7413b885c9bf900d402918cc848be08a59b022478804ea076b8"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:426f2fa71331a64f5132369ede5171c52fd1df1bd9727ce621f38b5b24f48750"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-win32.whl", hash = "sha256:33157920b233bc542ce497a81a2e1452e685a11834c5763933b440fedd1d8e2d"}, - {file = "SQLAlchemy-2.0.28-cp39-cp39-win_amd64.whl", hash = "sha256:2f60843068e432311c886c5f03c4664acaef507cf716f6c60d5fde7265be9d7b"}, - {file = "SQLAlchemy-2.0.28-py3-none-any.whl", hash = "sha256:78bb7e8da0183a8301352d569900d9d3594c48ac21dc1c2ec6b3121ed8b6c986"}, - {file = "SQLAlchemy-2.0.28.tar.gz", hash = "sha256:dd53b6c4e6d960600fd6532b79ee28e2da489322fcf6648738134587faf767b6"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d04e579e911562f1055d26dab1868d3e0bb905db3bccf664ee8ad109f035618a"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa67d821c1fd268a5a87922ef4940442513b4e6c377553506b9db3b83beebbd8"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c7a596d0be71b7baa037f4ac10d5e057d276f65a9a611c46970f012752ebf2d"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954d9735ee9c3fa74874c830d089a815b7b48df6f6b6e357a74130e478dbd951"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5cd20f58c29bbf2680039ff9f569fa6d21453fbd2fa84dbdb4092f006424c2e6"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:03f448ffb731b48323bda68bcc93152f751436ad6037f18a42b7e16af9e91c07"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-win32.whl", hash = "sha256:d997c5938a08b5e172c30583ba6b8aad657ed9901fc24caf3a7152eeccb2f1b4"}, + {file = "SQLAlchemy-2.0.27-cp310-cp310-win_amd64.whl", hash = "sha256:eb15ef40b833f5b2f19eeae65d65e191f039e71790dd565c2af2a3783f72262f"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c5bad7c60a392850d2f0fee8f355953abaec878c483dd7c3836e0089f046bf6"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3012ab65ea42de1be81fff5fb28d6db893ef978950afc8130ba707179b4284a"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbcd77c4d94b23e0753c5ed8deba8c69f331d4fd83f68bfc9db58bc8983f49cd"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d177b7e82f6dd5e1aebd24d9c3297c70ce09cd1d5d37b43e53f39514379c029c"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:680b9a36029b30cf063698755d277885d4a0eab70a2c7c6e71aab601323cba45"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1306102f6d9e625cebaca3d4c9c8f10588735ef877f0360b5cdb4fdfd3fd7131"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-win32.whl", hash = "sha256:5b78aa9f4f68212248aaf8943d84c0ff0f74efc65a661c2fc68b82d498311fd5"}, + {file = "SQLAlchemy-2.0.27-cp311-cp311-win_amd64.whl", hash = "sha256:15e19a84b84528f52a68143439d0c7a3a69befcd4f50b8ef9b7b69d2628ae7c4"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0de1263aac858f288a80b2071990f02082c51d88335a1db0d589237a3435fe71"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce850db091bf7d2a1f2fdb615220b968aeff3849007b1204bf6e3e50a57b3d32"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dfc936870507da96aebb43e664ae3a71a7b96278382bcfe84d277b88e379b18"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4fbe6a766301f2e8a4519f4500fe74ef0a8509a59e07a4085458f26228cd7cc"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4535c49d961fe9a77392e3a630a626af5baa967172d42732b7a43496c8b28876"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0fb3bffc0ced37e5aa4ac2416f56d6d858f46d4da70c09bb731a246e70bff4d5"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-win32.whl", hash = "sha256:7f470327d06400a0aa7926b375b8e8c3c31d335e0884f509fe272b3c700a7254"}, + {file = "SQLAlchemy-2.0.27-cp312-cp312-win_amd64.whl", hash = "sha256:f9374e270e2553653d710ece397df67db9d19c60d2647bcd35bfc616f1622dcd"}, + {file = "SQLAlchemy-2.0.27-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e97cf143d74a7a5a0f143aa34039b4fecf11343eed66538610debc438685db4a"}, + {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7b5a3e2120982b8b6bd1d5d99e3025339f7fb8b8267551c679afb39e9c7c7f1"}, + {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e36aa62b765cf9f43a003233a8c2d7ffdeb55bc62eaa0a0380475b228663a38f"}, + {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5ada0438f5b74c3952d916c199367c29ee4d6858edff18eab783b3978d0db16d"}, + {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b1d9d1bfd96eef3c3faedb73f486c89e44e64e40e5bfec304ee163de01cf996f"}, + {file = "SQLAlchemy-2.0.27-cp37-cp37m-win32.whl", hash = "sha256:ca891af9f3289d24a490a5fde664ea04fe2f4984cd97e26de7442a4251bd4b7c"}, + {file = "SQLAlchemy-2.0.27-cp37-cp37m-win_amd64.whl", hash = "sha256:fd8aafda7cdff03b905d4426b714601c0978725a19efc39f5f207b86d188ba01"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec1f5a328464daf7a1e4e385e4f5652dd9b1d12405075ccba1df842f7774b4fc"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad862295ad3f644e3c2c0d8b10a988e1600d3123ecb48702d2c0f26771f1c396"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48217be1de7d29a5600b5c513f3f7664b21d32e596d69582be0a94e36b8309cb"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e56afce6431450442f3ab5973156289bd5ec33dd618941283847c9fd5ff06bf"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:611068511b5531304137bcd7fe8117c985d1b828eb86043bd944cebb7fae3910"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b86abba762ecfeea359112b2bb4490802b340850bbee1948f785141a5e020de8"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-win32.whl", hash = "sha256:30d81cc1192dc693d49d5671cd40cdec596b885b0ce3b72f323888ab1c3863d5"}, + {file = "SQLAlchemy-2.0.27-cp38-cp38-win_amd64.whl", hash = "sha256:120af1e49d614d2525ac247f6123841589b029c318b9afbfc9e2b70e22e1827d"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d07ee7793f2aeb9b80ec8ceb96bc8cc08a2aec8a1b152da1955d64e4825fcbac"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb0845e934647232b6ff5150df37ceffd0b67b754b9fdbb095233deebcddbd4a"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc19ae2e07a067663dd24fca55f8ed06a288384f0e6e3910420bf4b1270cc51"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b90053be91973a6fb6020a6e44382c97739736a5a9d74e08cc29b196639eb979"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2f5c9dfb0b9ab5e3a8a00249534bdd838d943ec4cfb9abe176a6c33408430230"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33e8bde8fff203de50399b9039c4e14e42d4d227759155c21f8da4a47fc8053c"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-win32.whl", hash = "sha256:d873c21b356bfaf1589b89090a4011e6532582b3a8ea568a00e0c3aab09399dd"}, + {file = "SQLAlchemy-2.0.27-cp39-cp39-win_amd64.whl", hash = "sha256:ff2f1b7c963961d41403b650842dc2039175b906ab2093635d8319bef0b7d620"}, + {file = "SQLAlchemy-2.0.27-py3-none-any.whl", hash = "sha256:1ab4e0448018d01b142c916cc7119ca573803a4745cfe341b8f95657812700ac"}, + {file = "SQLAlchemy-2.0.27.tar.gz", hash = "sha256:86a6ed69a71fe6b88bf9331594fa390a2adda4a49b5c06f98e47bf0d392534f8"}, ] [package.dependencies] @@ -4906,13 +4870,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.28.0" +version = "0.27.1" description = "The lightning-fast ASGI server." optional = true python-versions = ">=3.8" files = [ - {file = "uvicorn-0.28.0-py3-none-any.whl", hash = "sha256:6623abbbe6176204a4226e67607b4d52cc60ff62cda0ff177613645cefa2ece1"}, - {file = "uvicorn-0.28.0.tar.gz", hash = "sha256:cab4473b5d1eaeb5a0f6375ac4bc85007ffc75c3cc1768816d9e5d589857b067"}, + {file = "uvicorn-0.27.1-py3-none-any.whl", hash = "sha256:5c89da2f3895767472a35556e539fd59f7edbe9b1e9c0e1c99eebeadc61838e4"}, + {file = "uvicorn-0.27.1.tar.gz", hash = "sha256:3d9a267296243532db80c83a959a3400502165ade2c1338dea4e67915fd4745a"}, ] [package.dependencies] @@ -5604,4 +5568,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "f7a5ab7c85e79920d41e45e9bbd17f0dbc1180c52d027235a656c270d9e79346" +content-hash = "8b4cc583653becb3be9f5bc4c34cdf5ced146ba32157a5bb4bdc7885291c0403" From f8c568318f1d95985ca75899e6b7e1fd789ca80a Mon Sep 17 00:00:00 2001 From: Isaac Miller Date: Sat, 9 Mar 2024 14:18:40 -0600 Subject: [PATCH 71/79] Update poetry.lock --- poetry.lock | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 30ec76981..1b336906d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -151,6 +151,30 @@ files = [ {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] +[[package]] +name = "anthropic" +version = "0.18.1" +description = "The official Python library for the anthropic API" +optional = true +python-versions = ">=3.7" +files = [ + {file = "anthropic-0.18.1-py3-none-any.whl", hash = "sha256:b85aee64f619ce1b1964ba733a09adc4053e7bc4e6d4186001229ec191099dcf"}, + {file = "anthropic-0.18.1.tar.gz", hash = "sha256:f5d1caafd43f6cc933a79753a93531605095f040a384f6a900c3de9c3fb6694e"}, +] + +[package.dependencies] +anyio = ">=3.5.0,<5" +distro = ">=1.7.0,<2" +httpx = ">=0.23.0,<1" +pydantic = ">=1.9.0,<3" +sniffio = "*" +tokenizers = ">=0.13.0" +typing-extensions = ">=4.7,<5" + +[package.extras] +bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] +vertex = ["google-auth (>=2,<3)"] + [[package]] name = "anyio" version = "4.3.0" @@ -871,6 +895,17 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] +[[package]] +name = "distro" +version = "1.9.0" +description = "Distro - an OS platform information API" +optional = true +python-versions = ">=3.6" +files = [ + {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, + {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, +] + [[package]] name = "dnspython" version = "2.6.1" @@ -5568,4 +5603,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "8b4cc583653becb3be9f5bc4c34cdf5ced146ba32157a5bb4bdc7885291c0403" +content-hash = "f7a5ab7c85e79920d41e45e9bbd17f0dbc1180c52d027235a656c270d9e79346" From edadecd989d98bab32f272316c8d8c23b23bf03c Mon Sep 17 00:00:00 2001 From: Arnav Singhvi Date: Sat, 9 Mar 2024 12:20:04 -0800 Subject: [PATCH 72/79] update with self.history --- docs/docs/deep-dive/language_model_clients/custom-lm-client.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/deep-dive/language_model_clients/custom-lm-client.mdx b/docs/docs/deep-dive/language_model_clients/custom-lm-client.mdx index edef34da3..b27f2cf20 100644 --- a/docs/docs/deep-dive/language_model_clients/custom-lm-client.mdx +++ b/docs/docs/deep-dive/language_model_clients/custom-lm-client.mdx @@ -52,6 +52,7 @@ def __init__(model, api_key): self.model = model self.api_key = api_key self.provider = "default" + self.history = [] self.base_url = "https://api.anthropic.com/v1/messages" ``` From 2560b2955c87b5aeb9f8ec0a22f4c87cd6d2c94c Mon Sep 17 00:00:00 2001 From: Darin <86675935+darinkishore@users.noreply.github.com> Date: Sat, 9 Mar 2024 22:19:25 -0800 Subject: [PATCH 73/79] higher poetry openai req --- pyproject.toml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 04204686d..d9ff8ccc6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,12 @@ classifiers = [ "Programming Language :: Python :: 3", # removed 3.8 "Programming Language :: Python :: 3.9", ] + # We have both project and tool.poetry.dependencies. Should we remove one? +# tool.poetry.dependencies is a convenience thing for poetry users. +# project dependencies function similarly to requirements.txt, +# `pip install .` will pull from pyproject.toml dependencies + dependencies = [ "backoff~=2.2.1", "joblib~=1.3.2", @@ -77,7 +82,7 @@ python = ">=3.9,<3.12" pydantic = "2.5.0" backoff = "^2.2.1" joblib = "^1.3.2" -openai = "^0.28.1" +openai = ">=0.28.1,<2.0.0" pandas = "^2.1.1" regex = "^2023.10.3" ujson = "^5.8.0" From ab65929f555a995b8462a53abe98250d67f38316 Mon Sep 17 00:00:00 2001 From: Thomas Dybdahl Ahle Date: Sun, 10 Mar 2024 11:38:15 -0700 Subject: [PATCH 74/79] Update README.md Updated table of contents --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d96788ce..72245aaf4 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ If you need help thinking about your task, we recently created a [Discord server 1. **[Tutorials & Documentation](#2-documentation)** 1. **[Framework Syntax](#3-syntax-youre-in-charge-of-the-workflowits-free-form-python-code)** 1. **[Compiling: Two Powerful Concepts](#4-two-powerful-concepts-signatures--teleprompters)** -1. **[FAQ: Is DSPy right for me?](#5-faq-is-dspy-right-for-me)** +1. **[Pydantic Types](#5-pydantic-types)** +1. **[FAQ: Is DSPy right for me?](#6-faq-is-dspy-right-for-me)** From d73efde0032d4160ea12db1e19ba2e66d42fc3a5 Mon Sep 17 00:00:00 2001 From: Raja Rajendran Date: Mon, 11 Mar 2024 00:22:08 +0530 Subject: [PATCH 75/79] run ruff check --fix-only dspy/retrieve/faiss_rm.py --- dspy/retrieve/faiss_rm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspy/retrieve/faiss_rm.py b/dspy/retrieve/faiss_rm.py index 37460f895..f321d8736 100755 --- a/dspy/retrieve/faiss_rm.py +++ b/dspy/retrieve/faiss_rm.py @@ -3,7 +3,7 @@ """ import logging -from typing import Union, Optional +from typing import Optional, Union import numpy as np From 0c1d1b1b2c9b5d6dc6d565a84bfd8f17c273669d Mon Sep 17 00:00:00 2001 From: Quajak Date: Sun, 10 Mar 2024 16:52:55 -0400 Subject: [PATCH 76/79] Fix return_all_scores in evaluate again to return all (#625) --- dspy/evaluate/evaluate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspy/evaluate/evaluate.py b/dspy/evaluate/evaluate.py index 1099ede89..486e4b68e 100644 --- a/dspy/evaluate/evaluate.py +++ b/dspy/evaluate/evaluate.py @@ -219,7 +219,7 @@ def wrapped_program(example_idx, example): ipython_display(HTML(message)) if return_all_scores and return_outputs: - return round(100 * ncorrect / ntotal, 2), results + return round(100 * ncorrect / ntotal, 2), results, [score for *_, score in reordered_devset] elif return_all_scores: return round(100 * ncorrect / ntotal, 2), [score for *_, score in reordered_devset] elif return_outputs: From a5bc0c94571cec1379fe65c0d038ba773dee4c52 Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Mon, 11 Mar 2024 18:15:09 +0100 Subject: [PATCH 77/79] fix neo4j docs --- docs/api/retrieval_model_clients/Neo4jRM.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/retrieval_model_clients/Neo4jRM.md b/docs/api/retrieval_model_clients/Neo4jRM.md index 2bb2ddd2f..6b408b780 100644 --- a/docs/api/retrieval_model_clients/Neo4jRM.md +++ b/docs/api/retrieval_model_clients/Neo4jRM.md @@ -78,6 +78,6 @@ retriever_model = Neo4jRM( results = retriever_model("Explore the significance of quantum computing", k=3) -for passage in results.passages: - print("Document:", result, "\n") +for passage in results: + print("Document:", passage, "\n") ``` From 2d845de186b5d47a34c3f843cfc250be679087c0 Mon Sep 17 00:00:00 2001 From: Thomas Dybdahl Ahle Date: Mon, 11 Mar 2024 11:53:43 -0700 Subject: [PATCH 78/79] Update 8-typed_predictors.md A few fixes to the typed docs --- .../building-blocks/8-typed_predictors.md | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/docs/building-blocks/8-typed_predictors.md b/docs/docs/building-blocks/8-typed_predictors.md index e8c7167c1..9fe1785f8 100644 --- a/docs/docs/building-blocks/8-typed_predictors.md +++ b/docs/docs/building-blocks/8-typed_predictors.md @@ -16,12 +16,12 @@ Let's take a simple task as an example i.e. given the `context` and `query`, the from pydantic import BaseModel, Field class Input(BaseModel): - context: str = Field(..., description="The context for the question") - query: str = Field(..., description="The question to be answered") + context: str = Field(description="The context for the question") + query: str = Field(description="The question to be answered") class Output(BaseModel): - answer: str = Field(..., description="The answer for the question") - factual_: float = Field(..., description="The confidence score for the answer") + answer: str = Field(description="The answer for the question") + confidence: float = Field(ge=0, le=1, description="The confidence score for the answer") ``` As you can see, we can describe the attributes by defining a simple Signature that takes in the input and returns the output. @@ -46,6 +46,11 @@ predictor = dspy.TypedPredictor(QASignature) Similar to other modules, we pass the `QASignature` to `dspy.TypedPredictor` which enforces the typed constraints. +And similarly to `dspy.Predict`, we can also use a "string signature", which we type as: +```python +predictor = dspy.TypedPredictor("input:Input -> output:Output") +``` + ### I/O in Typed Predictors Now let's test out the Typed Predictor by providing some sample input to the predictor and verifying the output type. We can create an `Input` instance and pass it to the predictor to get a dictionary of the output. @@ -62,8 +67,8 @@ prediction = predictor(input=doc_query_pair) Let's see the output and its type. ```python -answer = prediction['answer'] -confidence_score = prediction['confidence_score'] +answer = prediction.answer +confidence_score = prediction.confidence print(f"Prediction: {prediction}\n\n") print(f"Answer: {answer}, Answer Type: {type(answer)}") @@ -89,18 +94,18 @@ prediction = cot_predictor(input=doc_query_pair) While the `dspy.TypedPredictor` and `dspy.TypedChainOfThought` provide a convenient way to use typed predictors, you can also use them as decorators to enforce type constraints on the inputs and outputs of the function. This relies on the internal definitions of the Signature class and its function arguments, outputs, and docstrings. -``` -# Function name is output key - +```python @dspy.predictor -def qa_function(doc_query_pair: Input) -> Output: - """Answer the question based on the context and query provided, and on the scale of 10 tell how confident you are about the answer.""" +def answer(doc_query_pair: Input) -> Output: + """Answer the question based on the context and query provided, and on the scale of 0-1 tell how confident you are about the answer.""" pass @dspy.cot -def qa_function(doc_query_pair: Input) -> Output: - """Answer the question based on the context and query provided, and on the scale of 10 tell how confident you are about the answer.""" +def answer(doc_query_pair: Input) -> Output: + """Answer the question based on the context and query provided, and on the scale of 0-1 tell how confident you are about the answer.""" pass + +prediction = answer(doc_query_pair=doc_query_pair) ``` ## Composing Functional Typed Predictors in `dspy.Module` From e53fcbe8953e5d221f3b53d20049938c4e4d88bb Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Wed, 13 Mar 2024 17:47:24 +0100 Subject: [PATCH 79/79] fix(dspy): use DataFrame.applymap in older pandas --- dspy/evaluate/evaluate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dspy/evaluate/evaluate.py b/dspy/evaluate/evaluate.py index 486e4b68e..603b552aa 100644 --- a/dspy/evaluate/evaluate.py +++ b/dspy/evaluate/evaluate.py @@ -184,7 +184,10 @@ def wrapped_program(example_idx, example): df = pd.DataFrame(data) # Truncate every cell in the DataFrame - df = df.map(truncate_cell) + if hasattr(df, "map"): # DataFrame.applymap was renamed to DataFrame.map in Pandas 2.1.0 + df = df.map(truncate_cell) + else: + df = df.applymap(truncate_cell) # Rename the 'correct' column to the name of the metric object assert callable(metric)