prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Docstrings - `haystack.components.samplers`
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `haystack/components/samplers/top_p.py`
  Content:
  ```
  1 import logging
  2 from typing import List, Optional
  3 
  4 from haystack import ComponentError, Document, component
  5 from haystack.lazy_imports import LazyImport
  6 
  7 logger = logging.getLogger(__name__)
  8 
  9 
  10 with LazyImport(message="Run 'pip install \"torch>=1.13\"'") as torch_import:
  11     import torch
  12 
  13 
  14 @component
  15 class TopPSampler:
  16     """
  17     Implements top-p (nucleus) sampling for document filtering based on cumulative probability scores.
  18 
  19     This class provides functionality to filter a list of documents by selecting those whose scores fall
  20     within the top 'p' percent of the cumulative distribution. The method is useful for focusing on high-probability
  21     documents while filtering out less relevant ones based on their assigned scores.
  22 
  23     Usage example:
  24 
  25     ```python
  26     from haystack import Document
  27     from haystack.components.samplers import TopPSampler
  28 
  29     sampler = TopPSampler(top_p=0.95, score_field="similarity_score")
  30     docs = [
  31         Document(text="Berlin", meta={"similarity_score": -10.6}),
  32         Document(text="Belgrade", meta={"similarity_score": -8.9}),
  33         Document(text="Sarajevo", meta={"similarity_score": -4.6}),
  34     ]
  35     output = sampler.run(documents=docs)
  36     docs = output["documents"]
  37     assert len(docs) == 1
  38     assert docs[0].content == "Sarajevo"
  39     ```
  40     """
  41 
  42     def __init__(self, top_p: float = 1.0, score_field: Optional[str] = None):
  43         """
  44         Creates an instance of TopPSampler.
  45 
  46         :param top_p: Float between 0 and 1 representing the cumulative probability threshold for document selection.
  47         Defaults to 1.0, indicating no filtering (all documents are retained).
  48         :param score_field: Name of the field in each document's metadata that contains the score. If None, the default
  49         document score field is used.
  50         """
  51         torch_import.check()
  52 
  53         self.top_p = top_p
  54         self.score_field = score_field
  55 
  56     @component.output_types(documents=List[Document])
  57     def run(self, documents: List[Document], top_p: Optional[float] = None):
  58         """
  59         Filters documents using top-p sampling based on their scores.
  60 
  61         :param documents: List of Document objects to be filtered.
  62         :param top_p: Optional. A float to override the cumulative probability threshold set during initialization.
  63                  If None, the class's top_p value is used.
  64         :return: A dictionary with a key 'documents' containing the list of filtered Document objects.
  65 
  66         This method applies top-p sampling to filter out documents. It selects those documents whose similarity scores
  67         are within the top 'p' percent of the cumulative distribution, based on the specified or default top_p value.
  68 
  69         If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the
  70         method defaults to returning the document with the highest similarity score.
  71 
  72         :raises ValueError: If the top_p value is not within the range [0, 1].
  73         """
  74         if not documents:
  75             return {"documents": []}
  76 
  77         top_p = top_p or self.top_p or 1.0  # default to 1.0 if both are None
  78 
  79         if not 0 <= top_p <= 1:
  80             raise ValueError(f"top_p must be between 0 and 1. Got {top_p}.")
  81 
  82         similarity_scores = torch.tensor(self._collect_scores(documents), dtype=torch.float32)
  83 
  84         # Apply softmax normalization to the similarity scores
  85         probs = torch.nn.functional.softmax(similarity_scores, dim=-1)
  86 
  87         # Sort the probabilities and calculate their cumulative sum
  88         sorted_probs, sorted_indices = torch.sort(probs, descending=True)
  89         cumulative_probs = torch.cumsum(sorted_probs, dim=-1)
  90 
  91         # Check if the cumulative probabilities are close to top_p with a 1e-6 tolerance
  92         close_to_top_p = torch.isclose(cumulative_probs, torch.tensor(top_p, device=cumulative_probs.device), atol=1e-6)
  93 
  94         # Combine the close_to_top_p with original condition using logical OR
  95         condition = (cumulative_probs <= top_p) | close_to_top_p
  96 
  97         # Find the indices with cumulative probabilities that exceed top_p
  98         top_p_indices = torch.where(torch.BoolTensor(condition))[0]
  99 
  100         # Map the selected indices back to their original indices
  101         original_indices = sorted_indices[top_p_indices]
  102         selected_docs = [documents[i.item()] for i in original_indices]
  103 
  104         # If low p resulted in no documents being selected, then
  105         # return at least one document
  106         if not selected_docs:
  107             logger.warning(
  108                 "Top-p sampling with p=%s resulted in no documents being selected. "
  109                 "Returning the document with the highest similarity score.",
  110                 top_p,
  111             )
  112             highest_prob_indices = torch.argsort(probs, descending=True)
  113             selected_docs = [documents[int(highest_prob_indices[0].item())]]
  114 
  115         return {"documents": selected_docs}
  116 
  117     def _collect_scores(self, documents: List[Document]) -> List[float]:
  118         """
  119         Collect the scores from the documents' metadata.
  120         :param documents: List of Documents.
  121         :return: List of scores.
  122         """
  123         if self.score_field:
  124             missing_scores_docs = [d for d in documents if self.score_field not in d.meta]
  125             if missing_scores_docs:
  126                 missing_scores_docs_ids = [d.id for d in missing_scores_docs if d.id]
  127                 raise ComponentError(
  128                     f"Score field '{self.score_field}' not found in metadata of documents "
  129                     f"with IDs: {missing_scores_docs_ids}."
  130                     f"Make sure that all documents have a score field '{self.score_field}' in their metadata."
  131                 )
  132             return [d.meta[self.score_field] for d in documents]
  133         else:
  134             missing_scores_docs = [d for d in documents if d.score is None]
  135             if missing_scores_docs:
  136                 missing_scores_docs_ids = [d.id for d in missing_scores_docs if d.id]
  137                 raise ComponentError(
  138                     f"Ensure all documents have a valid score value. These docs  {missing_scores_docs_ids} don't."
  139                 )
  140             return [d.score for d in documents]  # type: ignore ## because Document score is Optional
  141
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/haystack/components/samplers/top_p.py b/haystack/components/samplers/top_p.py
  --- a/haystack/components/samplers/top_p.py
  +++ b/haystack/components/samplers/top_p.py
  @@ -16,8 +16,8 @@
       """
       Implements top-p (nucleus) sampling for document filtering based on cumulative probability scores.
   
  -    This class provides functionality to filter a list of documents by selecting those whose scores fall
  -    within the top 'p' percent of the cumulative distribution. The method is useful for focusing on high-probability
  +    This component provides functionality to filter a list of documents by selecting those whose scores fall
  +    within the top 'p' percent of the cumulative distribution. It is useful for focusing on high-probability
       documents while filtering out less relevant ones based on their assigned scores.
   
       Usage example:
  @@ -44,9 +44,9 @@
           Creates an instance of TopPSampler.
   
           :param top_p: Float between 0 and 1 representing the cumulative probability threshold for document selection.
  -        Defaults to 1.0, indicating no filtering (all documents are retained).
  +            A value of 1.0 indicates no filtering (all documents are retained).
           :param score_field: Name of the field in each document's metadata that contains the score. If None, the default
  -        document score field is used.
  +            document score field is used.
           """
           torch_import.check()
   
  @@ -57,17 +57,14 @@
       def run(self, documents: List[Document], top_p: Optional[float] = None):
           """
           Filters documents using top-p sampling based on their scores.
  +        If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the
  +        method returns the document with the highest similarity score.
   
           :param documents: List of Document objects to be filtered.
           :param top_p: Optional. A float to override the cumulative probability threshold set during initialization.
  -                 If None, the class's top_p value is used.
  -        :return: A dictionary with a key 'documents' containing the list of filtered Document objects.
  -
  -        This method applies top-p sampling to filter out documents. It selects those documents whose similarity scores
  -        are within the top 'p' percent of the cumulative distribution, based on the specified or default top_p value.
   
  -        If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the
  -        method defaults to returning the document with the highest similarity score.
  +        :returns: A dictionary with the following key:
  +            - `documents`: List of Document objects that have been selected based on the top-p sampling.
   
           :raises ValueError: If the top_p value is not within the range [0, 1].
           """
  
verification_info: {"golden_diff": "diff --git a/haystack/components/samplers/top_p.py b/haystack/components/samplers/top_p.py\n--- a/haystack/components/samplers/top_p.py\n+++ b/haystack/components/samplers/top_p.py\n@@ -16,8 +16,8 @@\n     \"\"\"\n     Implements top-p (nucleus) sampling for document filtering based on cumulative probability scores.\n \n-    This class provides functionality to filter a list of documents by selecting those whose scores fall\n-    within the top 'p' percent of the cumulative distribution. The method is useful for focusing on high-probability\n+    This component provides functionality to filter a list of documents by selecting those whose scores fall\n+    within the top 'p' percent of the cumulative distribution. It is useful for focusing on high-probability\n     documents while filtering out less relevant ones based on their assigned scores.\n \n     Usage example:\n@@ -44,9 +44,9 @@\n         Creates an instance of TopPSampler.\n \n         :param top_p: Float between 0 and 1 representing the cumulative probability threshold for document selection.\n-        Defaults to 1.0, indicating no filtering (all documents are retained).\n+            A value of 1.0 indicates no filtering (all documents are retained).\n         :param score_field: Name of the field in each document's metadata that contains the score. If None, the default\n-        document score field is used.\n+            document score field is used.\n         \"\"\"\n         torch_import.check()\n \n@@ -57,17 +57,14 @@\n     def run(self, documents: List[Document], top_p: Optional[float] = None):\n         \"\"\"\n         Filters documents using top-p sampling based on their scores.\n+        If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the\n+        method returns the document with the highest similarity score.\n \n         :param documents: List of Document objects to be filtered.\n         :param top_p: Optional. A float to override the cumulative probability threshold set during initialization.\n-                 If None, the class's top_p value is used.\n-        :return: A dictionary with a key 'documents' containing the list of filtered Document objects.\n-\n-        This method applies top-p sampling to filter out documents. It selects those documents whose similarity scores\n-        are within the top 'p' percent of the cumulative distribution, based on the specified or default top_p value.\n \n-        If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the\n-        method defaults to returning the document with the highest similarity score.\n+        :returns: A dictionary with the following key:\n+            - `documents`: List of Document objects that have been selected based on the top-p sampling.\n \n         :raises ValueError: If the top_p value is not within the range [0, 1].\n         \"\"\"\n", "issue": "Docstrings - `haystack.components.samplers`\n\n", "before_files": [{"content": "import logging\nfrom typing import List, Optional\n\nfrom haystack import ComponentError, Document, component\nfrom haystack.lazy_imports import LazyImport\n\nlogger = logging.getLogger(__name__)\n\n\nwith LazyImport(message=\"Run 'pip install \\\"torch>=1.13\\\"'\") as torch_import:\n    import torch\n\n\n@component\nclass TopPSampler:\n    \"\"\"\n    Implements top-p (nucleus) sampling for document filtering based on cumulative probability scores.\n\n    This class provides functionality to filter a list of documents by selecting those whose scores fall\n    within the top 'p' percent of the cumulative distribution. The method is useful for focusing on high-probability\n    documents while filtering out less relevant ones based on their assigned scores.\n\n    Usage example:\n\n    ```python\n    from haystack import Document\n    from haystack.components.samplers import TopPSampler\n\n    sampler = TopPSampler(top_p=0.95, score_field=\"similarity_score\")\n    docs = [\n        Document(text=\"Berlin\", meta={\"similarity_score\": -10.6}),\n        Document(text=\"Belgrade\", meta={\"similarity_score\": -8.9}),\n        Document(text=\"Sarajevo\", meta={\"similarity_score\": -4.6}),\n    ]\n    output = sampler.run(documents=docs)\n    docs = output[\"documents\"]\n    assert len(docs) == 1\n    assert docs[0].content == \"Sarajevo\"\n    ```\n    \"\"\"\n\n    def __init__(self, top_p: float = 1.0, score_field: Optional[str] = None):\n        \"\"\"\n        Creates an instance of TopPSampler.\n\n        :param top_p: Float between 0 and 1 representing the cumulative probability threshold for document selection.\n        Defaults to 1.0, indicating no filtering (all documents are retained).\n        :param score_field: Name of the field in each document's metadata that contains the score. If None, the default\n        document score field is used.\n        \"\"\"\n        torch_import.check()\n\n        self.top_p = top_p\n        self.score_field = score_field\n\n    @component.output_types(documents=List[Document])\n    def run(self, documents: List[Document], top_p: Optional[float] = None):\n        \"\"\"\n        Filters documents using top-p sampling based on their scores.\n\n        :param documents: List of Document objects to be filtered.\n        :param top_p: Optional. A float to override the cumulative probability threshold set during initialization.\n                 If None, the class's top_p value is used.\n        :return: A dictionary with a key 'documents' containing the list of filtered Document objects.\n\n        This method applies top-p sampling to filter out documents. It selects those documents whose similarity scores\n        are within the top 'p' percent of the cumulative distribution, based on the specified or default top_p value.\n\n        If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the\n        method defaults to returning the document with the highest similarity score.\n\n        :raises ValueError: If the top_p value is not within the range [0, 1].\n        \"\"\"\n        if not documents:\n            return {\"documents\": []}\n\n        top_p = top_p or self.top_p or 1.0  # default to 1.0 if both are None\n\n        if not 0 <= top_p <= 1:\n            raise ValueError(f\"top_p must be between 0 and 1. Got {top_p}.\")\n\n        similarity_scores = torch.tensor(self._collect_scores(documents), dtype=torch.float32)\n\n        # Apply softmax normalization to the similarity scores\n        probs = torch.nn.functional.softmax(similarity_scores, dim=-1)\n\n        # Sort the probabilities and calculate their cumulative sum\n        sorted_probs, sorted_indices = torch.sort(probs, descending=True)\n        cumulative_probs = torch.cumsum(sorted_probs, dim=-1)\n\n        # Check if the cumulative probabilities are close to top_p with a 1e-6 tolerance\n        close_to_top_p = torch.isclose(cumulative_probs, torch.tensor(top_p, device=cumulative_probs.device), atol=1e-6)\n\n        # Combine the close_to_top_p with original condition using logical OR\n        condition = (cumulative_probs <= top_p) | close_to_top_p\n\n        # Find the indices with cumulative probabilities that exceed top_p\n        top_p_indices = torch.where(torch.BoolTensor(condition))[0]\n\n        # Map the selected indices back to their original indices\n        original_indices = sorted_indices[top_p_indices]\n        selected_docs = [documents[i.item()] for i in original_indices]\n\n        # If low p resulted in no documents being selected, then\n        # return at least one document\n        if not selected_docs:\n            logger.warning(\n                \"Top-p sampling with p=%s resulted in no documents being selected. \"\n                \"Returning the document with the highest similarity score.\",\n                top_p,\n            )\n            highest_prob_indices = torch.argsort(probs, descending=True)\n            selected_docs = [documents[int(highest_prob_indices[0].item())]]\n\n        return {\"documents\": selected_docs}\n\n    def _collect_scores(self, documents: List[Document]) -> List[float]:\n        \"\"\"\n        Collect the scores from the documents' metadata.\n        :param documents: List of Documents.\n        :return: List of scores.\n        \"\"\"\n        if self.score_field:\n            missing_scores_docs = [d for d in documents if self.score_field not in d.meta]\n            if missing_scores_docs:\n                missing_scores_docs_ids = [d.id for d in missing_scores_docs if d.id]\n                raise ComponentError(\n                    f\"Score field '{self.score_field}' not found in metadata of documents \"\n                    f\"with IDs: {missing_scores_docs_ids}.\"\n                    f\"Make sure that all documents have a score field '{self.score_field}' in their metadata.\"\n                )\n            return [d.meta[self.score_field] for d in documents]\n        else:\n            missing_scores_docs = [d for d in documents if d.score is None]\n            if missing_scores_docs:\n                missing_scores_docs_ids = [d.id for d in missing_scores_docs if d.id]\n                raise ComponentError(\n                    f\"Ensure all documents have a valid score value. These docs  {missing_scores_docs_ids} don't.\"\n                )\n            return [d.score for d in documents]  # type: ignore ## because Document score is Optional\n", "path": "haystack/components/samplers/top_p.py"}], "after_files": [{"content": "import logging\nfrom typing import List, Optional\n\nfrom haystack import ComponentError, Document, component\nfrom haystack.lazy_imports import LazyImport\n\nlogger = logging.getLogger(__name__)\n\n\nwith LazyImport(message=\"Run 'pip install \\\"torch>=1.13\\\"'\") as torch_import:\n    import torch\n\n\n@component\nclass TopPSampler:\n    \"\"\"\n    Implements top-p (nucleus) sampling for document filtering based on cumulative probability scores.\n\n    This component provides functionality to filter a list of documents by selecting those whose scores fall\n    within the top 'p' percent of the cumulative distribution. It is useful for focusing on high-probability\n    documents while filtering out less relevant ones based on their assigned scores.\n\n    Usage example:\n\n    ```python\n    from haystack import Document\n    from haystack.components.samplers import TopPSampler\n\n    sampler = TopPSampler(top_p=0.95, score_field=\"similarity_score\")\n    docs = [\n        Document(text=\"Berlin\", meta={\"similarity_score\": -10.6}),\n        Document(text=\"Belgrade\", meta={\"similarity_score\": -8.9}),\n        Document(text=\"Sarajevo\", meta={\"similarity_score\": -4.6}),\n    ]\n    output = sampler.run(documents=docs)\n    docs = output[\"documents\"]\n    assert len(docs) == 1\n    assert docs[0].content == \"Sarajevo\"\n    ```\n    \"\"\"\n\n    def __init__(self, top_p: float = 1.0, score_field: Optional[str] = None):\n        \"\"\"\n        Creates an instance of TopPSampler.\n\n        :param top_p: Float between 0 and 1 representing the cumulative probability threshold for document selection.\n            A value of 1.0 indicates no filtering (all documents are retained).\n        :param score_field: Name of the field in each document's metadata that contains the score. If None, the default\n            document score field is used.\n        \"\"\"\n        torch_import.check()\n\n        self.top_p = top_p\n        self.score_field = score_field\n\n    @component.output_types(documents=List[Document])\n    def run(self, documents: List[Document], top_p: Optional[float] = None):\n        \"\"\"\n        Filters documents using top-p sampling based on their scores.\n        If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the\n        method returns the document with the highest similarity score.\n\n        :param documents: List of Document objects to be filtered.\n        :param top_p: Optional. A float to override the cumulative probability threshold set during initialization.\n\n        :returns: A dictionary with the following key:\n            - `documents`: List of Document objects that have been selected based on the top-p sampling.\n\n        :raises ValueError: If the top_p value is not within the range [0, 1].\n        \"\"\"\n        if not documents:\n            return {\"documents\": []}\n\n        top_p = top_p or self.top_p or 1.0  # default to 1.0 if both are None\n\n        if not 0 <= top_p <= 1:\n            raise ValueError(f\"top_p must be between 0 and 1. Got {top_p}.\")\n\n        similarity_scores = torch.tensor(self._collect_scores(documents), dtype=torch.float32)\n\n        # Apply softmax normalization to the similarity scores\n        probs = torch.nn.functional.softmax(similarity_scores, dim=-1)\n\n        # Sort the probabilities and calculate their cumulative sum\n        sorted_probs, sorted_indices = torch.sort(probs, descending=True)\n        cumulative_probs = torch.cumsum(sorted_probs, dim=-1)\n\n        # Check if the cumulative probabilities are close to top_p with a 1e-6 tolerance\n        close_to_top_p = torch.isclose(cumulative_probs, torch.tensor(top_p, device=cumulative_probs.device), atol=1e-6)\n\n        # Combine the close_to_top_p with original condition using logical OR\n        condition = (cumulative_probs <= top_p) | close_to_top_p\n\n        # Find the indices with cumulative probabilities that exceed top_p\n        top_p_indices = torch.where(torch.BoolTensor(condition))[0]\n\n        # Map the selected indices back to their original indices\n        original_indices = sorted_indices[top_p_indices]\n        selected_docs = [documents[i.item()] for i in original_indices]\n\n        # If low p resulted in no documents being selected, then\n        # return at least one document\n        if not selected_docs:\n            logger.warning(\n                \"Top-p sampling with p=%s resulted in no documents being selected. \"\n                \"Returning the document with the highest similarity score.\",\n                top_p,\n            )\n            highest_prob_indices = torch.argsort(probs, descending=True)\n            selected_docs = [documents[int(highest_prob_indices[0].item())]]\n\n        return {\"documents\": selected_docs}\n\n    def _collect_scores(self, documents: List[Document]) -> List[float]:\n        \"\"\"\n        Collect the scores from the documents' metadata.\n        :param documents: List of Documents.\n        :return: List of scores.\n        \"\"\"\n        if self.score_field:\n            missing_scores_docs = [d for d in documents if self.score_field not in d.meta]\n            if missing_scores_docs:\n                missing_scores_docs_ids = [d.id for d in missing_scores_docs if d.id]\n                raise ComponentError(\n                    f\"Score field '{self.score_field}' not found in metadata of documents \"\n                    f\"with IDs: {missing_scores_docs_ids}.\"\n                    f\"Make sure that all documents have a score field '{self.score_field}' in their metadata.\"\n                )\n            return [d.meta[self.score_field] for d in documents]\n        else:\n            missing_scores_docs = [d for d in documents if d.score is None]\n            if missing_scores_docs:\n                missing_scores_docs_ids = [d.id for d in missing_scores_docs if d.id]\n                raise ComponentError(\n                    f\"Ensure all documents have a valid score value. These docs  {missing_scores_docs_ids} don't.\"\n                )\n            return [d.score for d in documents]  # type: ignore ## because Document score is Optional\n", "path": "haystack/components/samplers/top_p.py"}]}