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()

```

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].
         """

{"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"}]}