From 2d93ea3abf2141bca2395ead36d28d9dff8bb413 Mon Sep 17 00:00:00 2001 From: HaystackBot Date: Mon, 1 Jul 2024 18:44:29 +0000 Subject: [PATCH 1/3] Update the changelog --- integrations/fastembed/CHANGELOG.md | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 integrations/fastembed/CHANGELOG.md diff --git a/integrations/fastembed/CHANGELOG.md b/integrations/fastembed/CHANGELOG.md new file mode 100644 index 000000000..9ae3da929 --- /dev/null +++ b/integrations/fastembed/CHANGELOG.md @@ -0,0 +1,63 @@ +# Changelog + +## [unreleased] + +### ⚙️ Miscellaneous Tasks + +- Retry tests to reduce flakyness (#836) +- Update ruff invocation to include check parameter (#853) + +### Fix + +- Typo on Sparse embedders. The parameter should be "progress_bar" … (#814) + +## [integrations/fastembed-v1.1.0] - 2024-05-15 + +## [integrations/fastembed-v1.0.0] - 2024-05-06 + +## [integrations/fastembed-v0.1.0] - 2024-04-10 + +### 🚀 Features + +- *(FastEmbed)* Support for SPLADE Sparse Embedder (#579) + +### 📚 Documentation + +- Disable-class-def (#556) + +## [integrations/fastembed-v0.0.6] - 2024-03-07 + +### 📚 Documentation + +- Review and normalize docstrings - `integrations.fastembed` (#519) +- Small consistency improvements (#536) + +## [integrations/fastembed-v0.0.5] - 2024-02-20 + +### 🐛 Bug Fixes + +- Fix order of API docs (#447) + +This PR will also push the docs to Readme + +### 📚 Documentation + +- Update category slug (#442) + +## [integrations/fastembed-v0.0.4] - 2024-02-16 + +## [integrations/fastembed-v0.0.3] - 2024-02-12 + +### 🐛 Bug Fixes + +- From numpy float to float (#391) + +### 📚 Documentation + +- Update paths and titles (#397) + +## [integrations/fastembed-v0.0.2] - 2024-02-11 + +## [integrations/fastembed-v0.0.1] - 2024-02-10 + + From 268b487a2e8633acecc917e51746eafb2040a9a6 Mon Sep 17 00:00:00 2001 From: Amna Mubashar Date: Tue, 2 Jul 2024 01:45:31 +0200 Subject: [PATCH 2/3] feat: made truncation optional for BedrockGenerator (#833) * Added truncate parameter to init method * fixed serialization bug for BedrockGenerator * Add a test to check truncation functionality --- .../generators/amazon_bedrock/generator.py | 10 ++++ .../amazon_bedrock/tests/test_generator.py | 47 +++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/integrations/amazon_bedrock/src/haystack_integrations/components/generators/amazon_bedrock/generator.py b/integrations/amazon_bedrock/src/haystack_integrations/components/generators/amazon_bedrock/generator.py index b93ba1d3f..32d1de629 100644 --- a/integrations/amazon_bedrock/src/haystack_integrations/components/generators/amazon_bedrock/generator.py +++ b/integrations/amazon_bedrock/src/haystack_integrations/components/generators/amazon_bedrock/generator.py @@ -75,6 +75,7 @@ def __init__( aws_region_name: Optional[Secret] = Secret.from_env_var("AWS_DEFAULT_REGION", strict=False), # noqa: B008 aws_profile_name: Optional[Secret] = Secret.from_env_var("AWS_PROFILE", strict=False), # noqa: B008 max_length: Optional[int] = 100, + truncate: Optional[bool] = True, **kwargs, ): """ @@ -87,6 +88,7 @@ def __init__( :param aws_region_name: The AWS region name. :param aws_profile_name: The AWS profile name. :param max_length: The maximum length of the generated text. + :param truncate: Whether to truncate the prompt or not. :param kwargs: Additional keyword arguments to be passed to the model. :raises ValueError: If the model name is empty or None. :raises AmazonBedrockConfigurationError: If the AWS environment is not configured correctly or the model is @@ -97,11 +99,13 @@ def __init__( raise ValueError(msg) self.model = model self.max_length = max_length + self.truncate = truncate self.aws_access_key_id = aws_access_key_id self.aws_secret_access_key = aws_secret_access_key self.aws_session_token = aws_session_token self.aws_region_name = aws_region_name self.aws_profile_name = aws_profile_name + self.kwargs = kwargs def resolve_secret(secret: Optional[Secret]) -> Optional[str]: return secret.resolve_value() if secret else None @@ -129,6 +133,7 @@ def resolve_secret(secret: Optional[Secret]) -> Optional[str]: # Truncate prompt if prompt tokens > model_max_length-max_length # (max_length is the length of the generated text) # we use GPT2 tokenizer which will likely provide good token count approximation + self.prompt_handler = DefaultPromptHandler( tokenizer="gpt2", model_max_length=model_max_length, @@ -189,6 +194,9 @@ def invoke(self, *args, **kwargs): ) raise ValueError(msg) + if self.truncate: + prompt = self._ensure_token_limit(prompt) + body = self.model_adapter.prepare_body(prompt=prompt, **kwargs) try: if stream: @@ -266,6 +274,8 @@ def to_dict(self) -> Dict[str, Any]: aws_profile_name=self.aws_profile_name.to_dict() if self.aws_profile_name else None, model=self.model, max_length=self.max_length, + truncate=self.truncate, + **self.kwargs, ) @classmethod diff --git a/integrations/amazon_bedrock/tests/test_generator.py b/integrations/amazon_bedrock/tests/test_generator.py index e603c8853..65463caae 100644 --- a/integrations/amazon_bedrock/tests/test_generator.py +++ b/integrations/amazon_bedrock/tests/test_generator.py @@ -20,10 +20,7 @@ def test_to_dict(mock_boto3_session): """ Test that the to_dict method returns the correct dictionary without aws credentials """ - generator = AmazonBedrockGenerator( - model="anthropic.claude-v2", - max_length=99, - ) + generator = AmazonBedrockGenerator(model="anthropic.claude-v2", max_length=99, truncate=False, temperature=10) expected_dict = { "type": "haystack_integrations.components.generators.amazon_bedrock.generator.AmazonBedrockGenerator", @@ -35,6 +32,8 @@ def test_to_dict(mock_boto3_session): "aws_profile_name": {"type": "env_var", "env_vars": ["AWS_PROFILE"], "strict": False}, "model": "anthropic.claude-v2", "max_length": 99, + "truncate": False, + "temperature": 10, }, } @@ -194,6 +193,46 @@ def test_long_prompt_is_truncated(mock_boto3_session): assert prompt_after_resize == truncated_prompt_text +def test_long_prompt_is_not_truncated_when_truncate_false(mock_boto3_session): + """ + Test that a long prompt is not truncated and _ensure_token_limit is not called when truncate is set to False + """ + long_prompt_text = "I am a tokenized prompt of length eight" + + # Our mock prompt is 8 tokens long, so it exceeds the total limit (8 prompt tokens + 3 generated tokens > 10 tokens) + max_length_generated_text = 3 + total_model_max_length = 10 + + with patch("transformers.AutoTokenizer.from_pretrained", return_value=MagicMock()): + generator = AmazonBedrockGenerator( + model="anthropic.claude-v2", + max_length=max_length_generated_text, + model_max_length=total_model_max_length, + truncate=False, + ) + + # Mock the _ensure_token_limit method to track if it is called + with patch.object( + generator, "_ensure_token_limit", wraps=generator._ensure_token_limit + ) as mock_ensure_token_limit: + # Mock the model adapter to avoid actual invocation + generator.model_adapter.prepare_body = MagicMock(return_value={}) + generator.client = MagicMock() + generator.client.invoke_model = MagicMock( + return_value={"body": MagicMock(read=MagicMock(return_value=b'{"generated_text": "response"}'))} + ) + generator.model_adapter.get_responses = MagicMock(return_value=["response"]) + + # Invoke the generator + generator.invoke(prompt=long_prompt_text) + + # Ensure _ensure_token_limit was not called + mock_ensure_token_limit.assert_not_called(), + + # Check the prompt passed to prepare_body + generator.model_adapter.prepare_body.assert_called_with(prompt=long_prompt_text) + + @pytest.mark.parametrize( "model, expected_model_adapter", [ From 06d77769199607c717cffa297d9b71e51bee4ed4 Mon Sep 17 00:00:00 2001 From: Stefano Fiorucci Date: Tue, 2 Jul 2024 09:50:43 +0200 Subject: [PATCH 3/3] refactor!: Qdrant - remove unused init parameters: `content_field`, `name_field`, `embedding_field`, and `duplicate_documents` (#861) * rm unused params * docs: change duplicate_documents to policy in docstring --------- Co-authored-by: Julian Risch --- .../document_stores/qdrant/converters.py | 5 ++-- .../document_stores/qdrant/document_store.py | 24 +------------------ .../qdrant/tests/test_dict_converters.py | 12 ---------- integrations/qdrant/tests/test_retriever.py | 12 ---------- 4 files changed, 3 insertions(+), 50 deletions(-) diff --git a/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/converters.py b/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/converters.py index 96bd4f37a..01645a999 100644 --- a/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/converters.py +++ b/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/converters.py @@ -17,7 +17,6 @@ def convert_haystack_documents_to_qdrant_points( documents: List[Document], *, - embedding_field: str, use_sparse_embeddings: bool, ) -> List[rest.PointStruct]: points = [] @@ -26,7 +25,7 @@ def convert_haystack_documents_to_qdrant_points( if use_sparse_embeddings: vector = {} - dense_vector = payload.pop(embedding_field, None) + dense_vector = payload.pop("embedding", None) if dense_vector is not None: vector[DENSE_VECTORS_NAME] = dense_vector @@ -36,7 +35,7 @@ def convert_haystack_documents_to_qdrant_points( vector[SPARSE_VECTORS_NAME] = sparse_vector_instance else: - vector = payload.pop(embedding_field) or {} + vector = payload.pop("embedding") or {} _id = convert_id(payload.get("id")) point = rest.PointStruct( diff --git a/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/document_store.py b/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/document_store.py index 51d64e5e3..f9b2190ad 100644 --- a/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/document_store.py +++ b/integrations/qdrant/src/haystack_integrations/document_stores/qdrant/document_store.py @@ -110,14 +110,10 @@ def __init__( index: str = "Document", embedding_dim: int = 768, on_disk: bool = False, - content_field: str = "content", - name_field: str = "name", - embedding_field: str = "embedding", use_sparse_embeddings: bool = False, similarity: str = "cosine", return_embedding: bool = False, progress_bar: bool = True, - duplicate_documents: str = "overwrite", recreate_index: bool = False, shard_number: Optional[int] = None, replication_factor: Optional[int] = None, @@ -170,12 +166,6 @@ def __init__( Dimension of the embeddings. :param on_disk: Whether to store the collection on disk. - :param content_field: - The field for the document content. - :param name_field: - The field for the document name. - :param embedding_field: - The field for the document embeddings. :param use_sparse_embedding: If set to `True`, enables support for sparse embeddings. :param similarity: @@ -184,8 +174,6 @@ def __init__( Whether to return embeddings in the search results. :param progress_bar: Whether to show a progress bar or not. - :param duplicate_documents: - The parameter is not used and will be removed in future release. :param recreate_index: Whether to recreate the index. :param shard_number: @@ -260,14 +248,10 @@ def __init__( self.use_sparse_embeddings = use_sparse_embeddings self.embedding_dim = embedding_dim self.on_disk = on_disk - self.content_field = content_field - self.name_field = name_field - self.embedding_field = embedding_field self.similarity = similarity self.index = index self.return_embedding = return_embedding self.progress_bar = progress_bar - self.duplicate_documents = duplicate_documents self.write_batch_size = write_batch_size self.scroll_size = scroll_size @@ -380,7 +364,6 @@ def write_documents( for document_batch in batched_documents: batch = convert_haystack_documents_to_qdrant_points( document_batch, - embedding_field=self.embedding_field, use_sparse_embeddings=self.use_sparse_embeddings, ) @@ -891,12 +874,7 @@ def _handle_duplicate_documents( :param documents: A list of Haystack Document objects. :param index: name of the index - :param duplicate_documents: Handle duplicate documents based on parameter options. - Parameter options : ( 'skip','overwrite','fail') - skip (default option): Ignore the duplicates documents. - overwrite: Update any existing documents with the same ID when adding documents. - fail: An error is raised if the document ID of the document being added already - exists. + :param policy: The duplicate policy to use when writing documents. :returns: A list of Haystack Document objects. """ diff --git a/integrations/qdrant/tests/test_dict_converters.py b/integrations/qdrant/tests/test_dict_converters.py index dd54df4c4..9fc8779f7 100644 --- a/integrations/qdrant/tests/test_dict_converters.py +++ b/integrations/qdrant/tests/test_dict_converters.py @@ -22,15 +22,11 @@ def test_to_dict(): "index": "test", "embedding_dim": 768, "on_disk": False, - "content_field": "content", - "name_field": "name", - "embedding_field": "embedding", "force_disable_check_same_thread": False, "use_sparse_embeddings": False, "similarity": "cosine", "return_embedding": False, "progress_bar": True, - "duplicate_documents": "overwrite", "recreate_index": False, "shard_number": None, "replication_factor": None, @@ -62,15 +58,11 @@ def test_from_dict(): "index": "test", "embedding_dim": 768, "on_disk": False, - "content_field": "content", - "name_field": "name", - "embedding_field": "embedding", "force_disable_check_same_thread": False, "use_sparse_embeddings": True, "similarity": "cosine", "return_embedding": False, "progress_bar": True, - "duplicate_documents": "overwrite", "recreate_index": True, "shard_number": None, "quantization_config": None, @@ -87,16 +79,12 @@ def test_from_dict(): assert all( [ document_store.index == "test", - document_store.content_field == "content", - document_store.name_field == "name", - document_store.embedding_field == "embedding", document_store.force_disable_check_same_thread is False, document_store.use_sparse_embeddings is True, document_store.on_disk is False, document_store.similarity == "cosine", document_store.return_embedding is False, document_store.progress_bar, - document_store.duplicate_documents == "overwrite", document_store.recreate_index is True, document_store.shard_number is None, document_store.replication_factor is None, diff --git a/integrations/qdrant/tests/test_retriever.py b/integrations/qdrant/tests/test_retriever.py index 2eb0f6a34..3bfb9e62e 100644 --- a/integrations/qdrant/tests/test_retriever.py +++ b/integrations/qdrant/tests/test_retriever.py @@ -47,15 +47,11 @@ def test_to_dict(self): "index": "test", "embedding_dim": 768, "on_disk": False, - "content_field": "content", - "name_field": "name", "force_disable_check_same_thread": False, - "embedding_field": "embedding", "use_sparse_embeddings": False, "similarity": "cosine", "return_embedding": False, "progress_bar": True, - "duplicate_documents": "overwrite", "recreate_index": False, "shard_number": None, "replication_factor": None, @@ -170,15 +166,11 @@ def test_to_dict(self): "index": "test", "embedding_dim": 768, "on_disk": False, - "content_field": "content", - "name_field": "name", - "embedding_field": "embedding", "force_disable_check_same_thread": False, "use_sparse_embeddings": False, "similarity": "cosine", "return_embedding": False, "progress_bar": True, - "duplicate_documents": "overwrite", "recreate_index": False, "shard_number": None, "replication_factor": None, @@ -280,15 +272,11 @@ def test_to_dict(self): "index": "test", "embedding_dim": 768, "on_disk": False, - "content_field": "content", - "name_field": "name", - "embedding_field": "embedding", "force_disable_check_same_thread": False, "use_sparse_embeddings": False, "similarity": "cosine", "return_embedding": False, "progress_bar": True, - "duplicate_documents": "overwrite", "recreate_index": False, "shard_number": None, "replication_factor": None,