We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow Chat Generators to connect to Answer Builder
**Is your feature request related to a problem? Please describe.**
There is no current way for a `ChatGenerator` to directly connect to `AnswerBuilder()` despite similar functionality to a regular Generator.

**Describe the solution you'd like**
We can extract the text from a `ChatMessage` and use it as a `str` as expected in the code for AnswerBuilder.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
ChatGenerators that rely on non-open ai models require a specific chat format to be applied to properly differentiate between system/user/assistant messages. This is done manually (and prone to errors) in regular generators. This is an example I pulled from a Haystack notebook:

```
prompt_template = """
<|begin_of_text|><|start_header_id|>user<|end_header_id|>


Using the information contained in the context, give a comprehensive answer to the question.
If the answer cannot be deduced from the context, do not give an answer.

Context:
  {% for doc in documents %}
  {{ doc.content }} URL:{{ doc.meta['url'] }}
  {% endfor %};
  Question: {{query}}<|eot_id|>

<|start_header_id|>assistant<|end_header_id|>


"""
prompt_builder = PromptBuilder(template=prompt_template)
```

This can be accomplished by using a `ChatGenerator` as follows:

```
system_message = ChatMessage.from_system(
    """
    Read the context provided and answer the question if possible.If you can not form an answer from the context, reply with "Nah".
    Context:
    {% for doc in documents %}
    {{ doc.content }}
    {% endfor %};
    """
)
user_message = ChatMessage.from_user("query: {{query}}")
assistent_message = ChatMessage.from_assistant("Answer: ")
```

We can then add the output to an `AnswerBuilder` to complete a pipeline ensuring that the proper template is applied.

--- 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/builders/answer_builder.py`
Content:
```
1 # SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
2 #
3 # SPDX-License-Identifier: Apache-2.0
4 
5 import re
6 from typing import Any, Dict, List, Optional
7 
8 from haystack import Document, GeneratedAnswer, component, logging
9 
10 logger = logging.getLogger(__name__)
11 
12 
13 @component
14 class AnswerBuilder:
15     """
16     Takes a query and the replies a Generator returns as input and parses them into GeneratedAnswer objects.
17 
18     Optionally, it also takes Documents and metadata from the Generator as inputs to enrich the GeneratedAnswer objects.
19 
20     Usage example:
21     ```python
22     from haystack.components.builders import AnswerBuilder
23 
24     builder = AnswerBuilder(pattern="Answer: (.*)")
25     builder.run(query="What's the answer?", replies=["This is an argument. Answer: This is the answer."])
26     ```
27     """
28 
29     def __init__(self, pattern: Optional[str] = None, reference_pattern: Optional[str] = None):
30         """
31         Creates an instance of the AnswerBuilder component.
32 
33         :param pattern:
34             The regular expression pattern to use to extract the answer text from the generator output.
35             If not specified, the whole string is used as the answer. The regular expression can have at
36             most one capture group. If a capture group is present, the text matched by the capture group
37             is used as the answer. If no capture group is present, the whole match is used as the answer.
38             Examples:
39                 `[^\\n]+$` finds "this is an answer" in a string "this is an argument.\\nthis is an answer".
40                 `Answer: (.*)` finds "this is an answer" in a string "this is an argument. Answer: this is an answer".
41 
42         :param reference_pattern:
43             The regular expression pattern to use for parsing the document references.
44             We assume that references are specified as indices of the input documents and that
45             indices start at 1.
46             Example: `\\[(\\d+)\\]` finds "1" in a string "this is an answer[1]".
47             If not specified, no parsing is done, and all documents are referenced.
48         """
49         if pattern:
50             AnswerBuilder._check_num_groups_in_regex(pattern)
51 
52         self.pattern = pattern
53         self.reference_pattern = reference_pattern
54 
55     @component.output_types(answers=List[GeneratedAnswer])
56     def run(
57         self,
58         query: str,
59         replies: List[str],
60         meta: Optional[List[Dict[str, Any]]] = None,
61         documents: Optional[List[Document]] = None,
62         pattern: Optional[str] = None,
63         reference_pattern: Optional[str] = None,
64     ):
65         """
66         Turns the output of a Generator into `Answer` objects using regular expressions.
67 
68         :param query:
69             The query used in the prompts for the Generator.
70         :param replies:
71             The output of the Generator.
72         :param meta:
73             The metadata returned by the Generator. If not specified, the generated answer will contain no metadata.
74         :param documents:
75             The documents used as input to the Generator. If `documents` are specified, they are added to the `Answer`
76             objects. If both `documents` and `reference_pattern` are specified, the documents referenced in the
77             Generator output are extracted from the input documents and added to the `Answer` objects.
78         :param pattern:
79             The regular expression pattern to use to extract the answer text from the generator output.
80             If not specified, the whole string is used as the answer. The regular expression can have at
81             most one capture group. If a capture group is present, the text matched by the capture group
82             is used as the answer. If no capture group is present, the whole match is used as the answer.
83                 Examples:
84                     `[^\\n]+$` finds "this is an answer" in a string "this is an argument.\\nthis is an answer".
85                     `Answer: (.*)` finds "this is an answer" in a string
86                     "this is an argument. Answer: this is an answer".
87         :param reference_pattern:
88             The regular expression pattern to use for parsing the document references.
89             We assume that references are specified as indices of the input documents and that indices start at 1.
90             Example: `\\[(\\d+)\\]` finds "1" in a string "this is an answer[1]".
91             If not specified, no parsing is done, and all documents are referenced.
92 
93         :returns: A dictionary with the following keys:
94             - `answers`: The answers obtained from the output of the generator
95         """
96         if not meta:
97             meta = [{}] * len(replies)
98         elif len(replies) != len(meta):
99             raise ValueError(f"Number of replies ({len(replies)}), and metadata ({len(meta)}) must match.")
100 
101         if pattern:
102             AnswerBuilder._check_num_groups_in_regex(pattern)
103 
104         pattern = pattern or self.pattern
105         reference_pattern = reference_pattern or self.reference_pattern
106 
107         all_answers = []
108         for reply, metadata in zip(replies, meta):
109             referenced_docs = []
110             if documents:
111                 reference_idxs = []
112                 if reference_pattern:
113                     reference_idxs = AnswerBuilder._extract_reference_idxs(reply, reference_pattern)
114                 else:
115                     reference_idxs = [doc_idx for doc_idx, _ in enumerate(documents)]
116 
117                 for idx in reference_idxs:
118                     try:
119                         referenced_docs.append(documents[idx])
120                     except IndexError:
121                         logger.warning(
122                             "Document index '{index}' referenced in Generator output is out of range. ", index=idx + 1
123                         )
124 
125             answer_string = AnswerBuilder._extract_answer_string(reply, pattern)
126             answer = GeneratedAnswer(data=answer_string, query=query, documents=referenced_docs, meta=metadata)
127             all_answers.append(answer)
128 
129         return {"answers": all_answers}
130 
131     @staticmethod
132     def _extract_answer_string(reply: str, pattern: Optional[str] = None) -> str:
133         """
134         Extract the answer string from the generator output using the specified pattern.
135 
136         If no pattern is specified, the whole string is used as the answer.
137 
138         :param reply:
139             The output of the Generator. A string.
140         :param pattern:
141             The regular expression pattern to use to extract the answer text from the generator output.
142         """
143         if pattern is None:
144             return reply
145 
146         if match := re.search(pattern, reply):
147             # No capture group in pattern -> use the whole match as answer
148             if not match.lastindex:
149                 return match.group(0)
150             # One capture group in pattern -> use the capture group as answer
151             return match.group(1)
152         return ""
153 
154     @staticmethod
155     def _extract_reference_idxs(reply: str, reference_pattern: str) -> List[int]:
156         document_idxs = re.findall(reference_pattern, reply)
157         return [int(idx) - 1 for idx in document_idxs]
158 
159     @staticmethod
160     def _check_num_groups_in_regex(pattern: str):
161         num_groups = re.compile(pattern).groups
162         if num_groups > 1:
163             raise ValueError(
164                 f"Pattern '{pattern}' contains multiple capture groups. "
165                 f"Please specify a pattern with at most one capture group."
166             )
167
```
--- 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/builders/answer_builder.py b/haystack/components/builders/answer_builder.py
--- a/haystack/components/builders/answer_builder.py
+++ b/haystack/components/builders/answer_builder.py
@@ -3,9 +3,10 @@
 # SPDX-License-Identifier: Apache-2.0
 
 import re
-from typing import Any, Dict, List, Optional
+from typing import Any, Dict, List, Optional, Union
 
 from haystack import Document, GeneratedAnswer, component, logging
+from haystack.dataclasses.chat_message import ChatMessage
 
 logger = logging.getLogger(__name__)
 
@@ -56,7 +57,7 @@
     def run(
         self,
         query: str,
-        replies: List[str],
+        replies: Union[List[str], List[ChatMessage]],
         meta: Optional[List[Dict[str, Any]]] = None,
         documents: Optional[List[Document]] = None,
         pattern: Optional[str] = None,
@@ -68,7 +69,7 @@
         :param query:
             The query used in the prompts for the Generator.
         :param replies:
-            The output of the Generator.
+            The output of the Generator. Can be a list of strings or a list of ChatMessage objects.
         :param meta:
             The metadata returned by the Generator. If not specified, the generated answer will contain no metadata.
         :param documents:
@@ -103,14 +104,15 @@
 
         pattern = pattern or self.pattern
         reference_pattern = reference_pattern or self.reference_pattern
-
         all_answers = []
         for reply, metadata in zip(replies, meta):
+            # Extract content from ChatMessage objects if reply is a ChatMessages, else use the string as is
+            extracted_reply: str = reply.content if isinstance(reply, ChatMessage) else reply  # type: ignore
+            extracted_metadata = reply.meta if isinstance(reply, ChatMessage) else metadata
             referenced_docs = []
             if documents:
-                reference_idxs = []
                 if reference_pattern:
-                    reference_idxs = AnswerBuilder._extract_reference_idxs(reply, reference_pattern)
+                    reference_idxs = AnswerBuilder._extract_reference_idxs(extracted_reply, reference_pattern)
                 else:
                     reference_idxs = [doc_idx for doc_idx, _ in enumerate(documents)]
 
@@ -122,8 +124,10 @@
                             "Document index '{index}' referenced in Generator output is out of range. ", index=idx + 1
                         )
 
-            answer_string = AnswerBuilder._extract_answer_string(reply, pattern)
-            answer = GeneratedAnswer(data=answer_string, query=query, documents=referenced_docs, meta=metadata)
+            answer_string = AnswerBuilder._extract_answer_string(extracted_reply, pattern)
+            answer = GeneratedAnswer(
+                data=answer_string, query=query, documents=referenced_docs, meta=extracted_metadata
+            )
             all_answers.append(answer)
 
         return {"answers": all_answers}

{"golden_diff": "diff --git a/haystack/components/builders/answer_builder.py b/haystack/components/builders/answer_builder.py\n--- a/haystack/components/builders/answer_builder.py\n+++ b/haystack/components/builders/answer_builder.py\n@@ -3,9 +3,10 @@\n # SPDX-License-Identifier: Apache-2.0\n \n import re\n-from typing import Any, Dict, List, Optional\n+from typing import Any, Dict, List, Optional, Union\n \n from haystack import Document, GeneratedAnswer, component, logging\n+from haystack.dataclasses.chat_message import ChatMessage\n \n logger = logging.getLogger(__name__)\n \n@@ -56,7 +57,7 @@\n     def run(\n         self,\n         query: str,\n-        replies: List[str],\n+        replies: Union[List[str], List[ChatMessage]],\n         meta: Optional[List[Dict[str, Any]]] = None,\n         documents: Optional[List[Document]] = None,\n         pattern: Optional[str] = None,\n@@ -68,7 +69,7 @@\n         :param query:\n             The query used in the prompts for the Generator.\n         :param replies:\n-            The output of the Generator.\n+            The output of the Generator. Can be a list of strings or a list of ChatMessage objects.\n         :param meta:\n             The metadata returned by the Generator. If not specified, the generated answer will contain no metadata.\n         :param documents:\n@@ -103,14 +104,15 @@\n \n         pattern = pattern or self.pattern\n         reference_pattern = reference_pattern or self.reference_pattern\n-\n         all_answers = []\n         for reply, metadata in zip(replies, meta):\n+            # Extract content from ChatMessage objects if reply is a ChatMessages, else use the string as is\n+            extracted_reply: str = reply.content if isinstance(reply, ChatMessage) else reply  # type: ignore\n+            extracted_metadata = reply.meta if isinstance(reply, ChatMessage) else metadata\n             referenced_docs = []\n             if documents:\n-                reference_idxs = []\n                 if reference_pattern:\n-                    reference_idxs = AnswerBuilder._extract_reference_idxs(reply, reference_pattern)\n+                    reference_idxs = AnswerBuilder._extract_reference_idxs(extracted_reply, reference_pattern)\n                 else:\n                     reference_idxs = [doc_idx for doc_idx, _ in enumerate(documents)]\n \n@@ -122,8 +124,10 @@\n                             \"Document index '{index}' referenced in Generator output is out of range. \", index=idx + 1\n                         )\n \n-            answer_string = AnswerBuilder._extract_answer_string(reply, pattern)\n-            answer = GeneratedAnswer(data=answer_string, query=query, documents=referenced_docs, meta=metadata)\n+            answer_string = AnswerBuilder._extract_answer_string(extracted_reply, pattern)\n+            answer = GeneratedAnswer(\n+                data=answer_string, query=query, documents=referenced_docs, meta=extracted_metadata\n+            )\n             all_answers.append(answer)\n \n         return {\"answers\": all_answers}\n", "issue": "Allow Chat Generators to connect to Answer Builder\n**Is your feature request related to a problem? Please describe.**\r\nThere is no current way for a `ChatGenerator` to directly connect to `AnswerBuilder()` despite similar functionality to a regular Generator.\r\n\r\n**Describe the solution you'd like**\r\nWe can extract the text from a `ChatMessage` and use it as a `str` as expected in the code for AnswerBuilder.\r\n\r\n**Describe alternatives you've considered**\r\nA clear and concise description of any alternative solutions or features you've considered.\r\n\r\n**Additional context**\r\nChatGenerators that rely on non-open ai models require a specific chat format to be applied to properly differentiate between system/user/assistant messages. This is done manually (and prone to errors) in regular generators. This is an example I pulled from a Haystack notebook:\r\n\r\n```\r\nprompt_template = \"\"\"\r\n<|begin_of_text|><|start_header_id|>user<|end_header_id|>\r\n\r\n\r\nUsing the information contained in the context, give a comprehensive answer to the question.\r\nIf the answer cannot be deduced from the context, do not give an answer.\r\n\r\nContext:\r\n  {% for doc in documents %}\r\n  {{ doc.content }} URL:{{ doc.meta['url'] }}\r\n  {% endfor %};\r\n  Question: {{query}}<|eot_id|>\r\n\r\n<|start_header_id|>assistant<|end_header_id|>\r\n\r\n\r\n\"\"\"\r\nprompt_builder = PromptBuilder(template=prompt_template)\r\n```\r\n\r\nThis can be accomplished by using a `ChatGenerator` as follows:\r\n\r\n```\r\nsystem_message = ChatMessage.from_system(\r\n    \"\"\"\r\n    Read the context provided and answer the question if possible.If you can not form an answer from the context, reply with \"Nah\".\r\n    Context:\r\n    {% for doc in documents %}\r\n    {{ doc.content }}\r\n    {% endfor %};\r\n    \"\"\"\r\n)\r\nuser_message = ChatMessage.from_user(\"query: {{query}}\")\r\nassistent_message = ChatMessage.from_assistant(\"Answer: \")\r\n```\r\n\r\nWe can then add the output to an `AnswerBuilder` to complete a pipeline ensuring that the proper template is applied.\n", "before_files": [{"content": "# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>\n#\n# SPDX-License-Identifier: Apache-2.0\n\nimport re\nfrom typing import Any, Dict, List, Optional\n\nfrom haystack import Document, GeneratedAnswer, component, logging\n\nlogger = logging.getLogger(__name__)\n\n\n@component\nclass AnswerBuilder:\n    \"\"\"\n    Takes a query and the replies a Generator returns as input and parses them into GeneratedAnswer objects.\n\n    Optionally, it also takes Documents and metadata from the Generator as inputs to enrich the GeneratedAnswer objects.\n\n    Usage example:\n    ```python\n    from haystack.components.builders import AnswerBuilder\n\n    builder = AnswerBuilder(pattern=\"Answer: (.*)\")\n    builder.run(query=\"What's the answer?\", replies=[\"This is an argument. Answer: This is the answer.\"])\n    ```\n    \"\"\"\n\n    def __init__(self, pattern: Optional[str] = None, reference_pattern: Optional[str] = None):\n        \"\"\"\n        Creates an instance of the AnswerBuilder component.\n\n        :param pattern:\n            The regular expression pattern to use to extract the answer text from the generator output.\n            If not specified, the whole string is used as the answer. The regular expression can have at\n            most one capture group. If a capture group is present, the text matched by the capture group\n            is used as the answer. If no capture group is present, the whole match is used as the answer.\n            Examples:\n                `[^\\\\n]+$` finds \"this is an answer\" in a string \"this is an argument.\\\\nthis is an answer\".\n                `Answer: (.*)` finds \"this is an answer\" in a string \"this is an argument. Answer: this is an answer\".\n\n        :param reference_pattern:\n            The regular expression pattern to use for parsing the document references.\n            We assume that references are specified as indices of the input documents and that\n            indices start at 1.\n            Example: `\\\\[(\\\\d+)\\\\]` finds \"1\" in a string \"this is an answer[1]\".\n            If not specified, no parsing is done, and all documents are referenced.\n        \"\"\"\n        if pattern:\n            AnswerBuilder._check_num_groups_in_regex(pattern)\n\n        self.pattern = pattern\n        self.reference_pattern = reference_pattern\n\n    @component.output_types(answers=List[GeneratedAnswer])\n    def run(\n        self,\n        query: str,\n        replies: List[str],\n        meta: Optional[List[Dict[str, Any]]] = None,\n        documents: Optional[List[Document]] = None,\n        pattern: Optional[str] = None,\n        reference_pattern: Optional[str] = None,\n    ):\n        \"\"\"\n        Turns the output of a Generator into `Answer` objects using regular expressions.\n\n        :param query:\n            The query used in the prompts for the Generator.\n        :param replies:\n            The output of the Generator.\n        :param meta:\n            The metadata returned by the Generator. If not specified, the generated answer will contain no metadata.\n        :param documents:\n            The documents used as input to the Generator. If `documents` are specified, they are added to the `Answer`\n            objects. If both `documents` and `reference_pattern` are specified, the documents referenced in the\n            Generator output are extracted from the input documents and added to the `Answer` objects.\n        :param pattern:\n            The regular expression pattern to use to extract the answer text from the generator output.\n            If not specified, the whole string is used as the answer. The regular expression can have at\n            most one capture group. If a capture group is present, the text matched by the capture group\n            is used as the answer. If no capture group is present, the whole match is used as the answer.\n                Examples:\n                    `[^\\\\n]+$` finds \"this is an answer\" in a string \"this is an argument.\\\\nthis is an answer\".\n                    `Answer: (.*)` finds \"this is an answer\" in a string\n                    \"this is an argument. Answer: this is an answer\".\n        :param reference_pattern:\n            The regular expression pattern to use for parsing the document references.\n            We assume that references are specified as indices of the input documents and that indices start at 1.\n            Example: `\\\\[(\\\\d+)\\\\]` finds \"1\" in a string \"this is an answer[1]\".\n            If not specified, no parsing is done, and all documents are referenced.\n\n        :returns: A dictionary with the following keys:\n            - `answers`: The answers obtained from the output of the generator\n        \"\"\"\n        if not meta:\n            meta = [{}] * len(replies)\n        elif len(replies) != len(meta):\n            raise ValueError(f\"Number of replies ({len(replies)}), and metadata ({len(meta)}) must match.\")\n\n        if pattern:\n            AnswerBuilder._check_num_groups_in_regex(pattern)\n\n        pattern = pattern or self.pattern\n        reference_pattern = reference_pattern or self.reference_pattern\n\n        all_answers = []\n        for reply, metadata in zip(replies, meta):\n            referenced_docs = []\n            if documents:\n                reference_idxs = []\n                if reference_pattern:\n                    reference_idxs = AnswerBuilder._extract_reference_idxs(reply, reference_pattern)\n                else:\n                    reference_idxs = [doc_idx for doc_idx, _ in enumerate(documents)]\n\n                for idx in reference_idxs:\n                    try:\n                        referenced_docs.append(documents[idx])\n                    except IndexError:\n                        logger.warning(\n                            \"Document index '{index}' referenced in Generator output is out of range. \", index=idx + 1\n                        )\n\n            answer_string = AnswerBuilder._extract_answer_string(reply, pattern)\n            answer = GeneratedAnswer(data=answer_string, query=query, documents=referenced_docs, meta=metadata)\n            all_answers.append(answer)\n\n        return {\"answers\": all_answers}\n\n    @staticmethod\n    def _extract_answer_string(reply: str, pattern: Optional[str] = None) -> str:\n        \"\"\"\n        Extract the answer string from the generator output using the specified pattern.\n\n        If no pattern is specified, the whole string is used as the answer.\n\n        :param reply:\n            The output of the Generator. A string.\n        :param pattern:\n            The regular expression pattern to use to extract the answer text from the generator output.\n        \"\"\"\n        if pattern is None:\n            return reply\n\n        if match := re.search(pattern, reply):\n            # No capture group in pattern -> use the whole match as answer\n            if not match.lastindex:\n                return match.group(0)\n            # One capture group in pattern -> use the capture group as answer\n            return match.group(1)\n        return \"\"\n\n    @staticmethod\n    def _extract_reference_idxs(reply: str, reference_pattern: str) -> List[int]:\n        document_idxs = re.findall(reference_pattern, reply)\n        return [int(idx) - 1 for idx in document_idxs]\n\n    @staticmethod\n    def _check_num_groups_in_regex(pattern: str):\n        num_groups = re.compile(pattern).groups\n        if num_groups > 1:\n            raise ValueError(\n                f\"Pattern '{pattern}' contains multiple capture groups. \"\n                f\"Please specify a pattern with at most one capture group.\"\n            )\n", "path": "haystack/components/builders/answer_builder.py"}], "after_files": [{"content": "# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>\n#\n# SPDX-License-Identifier: Apache-2.0\n\nimport re\nfrom typing import Any, Dict, List, Optional, Union\n\nfrom haystack import Document, GeneratedAnswer, component, logging\nfrom haystack.dataclasses.chat_message import ChatMessage\n\nlogger = logging.getLogger(__name__)\n\n\n@component\nclass AnswerBuilder:\n    \"\"\"\n    Takes a query and the replies a Generator returns as input and parses them into GeneratedAnswer objects.\n\n    Optionally, it also takes Documents and metadata from the Generator as inputs to enrich the GeneratedAnswer objects.\n\n    Usage example:\n    ```python\n    from haystack.components.builders import AnswerBuilder\n\n    builder = AnswerBuilder(pattern=\"Answer: (.*)\")\n    builder.run(query=\"What's the answer?\", replies=[\"This is an argument. Answer: This is the answer.\"])\n    ```\n    \"\"\"\n\n    def __init__(self, pattern: Optional[str] = None, reference_pattern: Optional[str] = None):\n        \"\"\"\n        Creates an instance of the AnswerBuilder component.\n\n        :param pattern:\n            The regular expression pattern to use to extract the answer text from the generator output.\n            If not specified, the whole string is used as the answer. The regular expression can have at\n            most one capture group. If a capture group is present, the text matched by the capture group\n            is used as the answer. If no capture group is present, the whole match is used as the answer.\n            Examples:\n                `[^\\\\n]+$` finds \"this is an answer\" in a string \"this is an argument.\\\\nthis is an answer\".\n                `Answer: (.*)` finds \"this is an answer\" in a string \"this is an argument. Answer: this is an answer\".\n\n        :param reference_pattern:\n            The regular expression pattern to use for parsing the document references.\n            We assume that references are specified as indices of the input documents and that\n            indices start at 1.\n            Example: `\\\\[(\\\\d+)\\\\]` finds \"1\" in a string \"this is an answer[1]\".\n            If not specified, no parsing is done, and all documents are referenced.\n        \"\"\"\n        if pattern:\n            AnswerBuilder._check_num_groups_in_regex(pattern)\n\n        self.pattern = pattern\n        self.reference_pattern = reference_pattern\n\n    @component.output_types(answers=List[GeneratedAnswer])\n    def run(\n        self,\n        query: str,\n        replies: Union[List[str], List[ChatMessage]],\n        meta: Optional[List[Dict[str, Any]]] = None,\n        documents: Optional[List[Document]] = None,\n        pattern: Optional[str] = None,\n        reference_pattern: Optional[str] = None,\n    ):\n        \"\"\"\n        Turns the output of a Generator into `Answer` objects using regular expressions.\n\n        :param query:\n            The query used in the prompts for the Generator.\n        :param replies:\n            The output of the Generator. Can be a list of strings or a list of ChatMessage objects.\n        :param meta:\n            The metadata returned by the Generator. If not specified, the generated answer will contain no metadata.\n        :param documents:\n            The documents used as input to the Generator. If `documents` are specified, they are added to the `Answer`\n            objects. If both `documents` and `reference_pattern` are specified, the documents referenced in the\n            Generator output are extracted from the input documents and added to the `Answer` objects.\n        :param pattern:\n            The regular expression pattern to use to extract the answer text from the generator output.\n            If not specified, the whole string is used as the answer. The regular expression can have at\n            most one capture group. If a capture group is present, the text matched by the capture group\n            is used as the answer. If no capture group is present, the whole match is used as the answer.\n                Examples:\n                    `[^\\\\n]+$` finds \"this is an answer\" in a string \"this is an argument.\\\\nthis is an answer\".\n                    `Answer: (.*)` finds \"this is an answer\" in a string\n                    \"this is an argument. Answer: this is an answer\".\n        :param reference_pattern:\n            The regular expression pattern to use for parsing the document references.\n            We assume that references are specified as indices of the input documents and that indices start at 1.\n            Example: `\\\\[(\\\\d+)\\\\]` finds \"1\" in a string \"this is an answer[1]\".\n            If not specified, no parsing is done, and all documents are referenced.\n\n        :returns: A dictionary with the following keys:\n            - `answers`: The answers obtained from the output of the generator\n        \"\"\"\n        if not meta:\n            meta = [{}] * len(replies)\n        elif len(replies) != len(meta):\n            raise ValueError(f\"Number of replies ({len(replies)}), and metadata ({len(meta)}) must match.\")\n\n        if pattern:\n            AnswerBuilder._check_num_groups_in_regex(pattern)\n\n        pattern = pattern or self.pattern\n        reference_pattern = reference_pattern or self.reference_pattern\n        all_answers = []\n        for reply, metadata in zip(replies, meta):\n            # Extract content from ChatMessage objects if reply is a ChatMessages, else use the string as is\n            extracted_reply: str = reply.content if isinstance(reply, ChatMessage) else reply  # type: ignore\n            extracted_metadata = reply.meta if isinstance(reply, ChatMessage) else metadata\n            referenced_docs = []\n            if documents:\n                if reference_pattern:\n                    reference_idxs = AnswerBuilder._extract_reference_idxs(extracted_reply, reference_pattern)\n                else:\n                    reference_idxs = [doc_idx for doc_idx, _ in enumerate(documents)]\n\n                for idx in reference_idxs:\n                    try:\n                        referenced_docs.append(documents[idx])\n                    except IndexError:\n                        logger.warning(\n                            \"Document index '{index}' referenced in Generator output is out of range. \", index=idx + 1\n                        )\n\n            answer_string = AnswerBuilder._extract_answer_string(extracted_reply, pattern)\n            answer = GeneratedAnswer(\n                data=answer_string, query=query, documents=referenced_docs, meta=extracted_metadata\n            )\n            all_answers.append(answer)\n\n        return {\"answers\": all_answers}\n\n    @staticmethod\n    def _extract_answer_string(reply: str, pattern: Optional[str] = None) -> str:\n        \"\"\"\n        Extract the answer string from the generator output using the specified pattern.\n\n        If no pattern is specified, the whole string is used as the answer.\n\n        :param reply:\n            The output of the Generator. A string.\n        :param pattern:\n            The regular expression pattern to use to extract the answer text from the generator output.\n        \"\"\"\n        if pattern is None:\n            return reply\n\n        if match := re.search(pattern, reply):\n            # No capture group in pattern -> use the whole match as answer\n            if not match.lastindex:\n                return match.group(0)\n            # One capture group in pattern -> use the capture group as answer\n            return match.group(1)\n        return \"\"\n\n    @staticmethod\n    def _extract_reference_idxs(reply: str, reference_pattern: str) -> List[int]:\n        document_idxs = re.findall(reference_pattern, reply)\n        return [int(idx) - 1 for idx in document_idxs]\n\n    @staticmethod\n    def _check_num_groups_in_regex(pattern: str):\n        num_groups = re.compile(pattern).groups\n        if num_groups > 1:\n            raise ValueError(\n                f\"Pattern '{pattern}' contains multiple capture groups. \"\n                f\"Please specify a pattern with at most one capture group.\"\n            )\n", "path": "haystack/components/builders/answer_builder.py"}]}