prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  `HTMLToDocument` to add `ByteStream` metadata to Document 
  `HTMLToDocument` converter, when receiving a `ByteStream` from the `LinkContentFetcher` does not add the url to the metadata of the Document. The URL is in the metadata of the ByteStream
  
  
  --- 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/preview/components/file_converters/html.py`
  Content:
  ```
  1 import logging
  2 from typing import List, Union
  3 from pathlib import Path
  4 
  5 from haystack.preview import Document, component
  6 from haystack.preview.dataclasses import ByteStream
  7 from haystack.preview.lazy_imports import LazyImport
  8 
  9 logger = logging.getLogger(__name__)
  10 
  11 with LazyImport("Run 'pip install boilerpy3'") as boilerpy3_import:
  12     from boilerpy3 import extractors
  13 
  14 
  15 @component
  16 class HTMLToDocument:
  17     """
  18     Converts an HTML file to a Document.
  19     """
  20 
  21     def __init__(self):
  22         """
  23         Initializes the HTMLToDocument component.
  24         """
  25         boilerpy3_import.check()
  26 
  27     @component.output_types(documents=List[Document])
  28     def run(self, sources: List[Union[str, Path, ByteStream]]):
  29         """
  30         Converts a list of HTML files to Documents.
  31 
  32         :param sources: List of HTML file paths or ByteStream objects.
  33         :return: List of converted Documents.
  34         """
  35         documents = []
  36         extractor = extractors.ArticleExtractor(raise_on_failure=False)
  37         for source in sources:
  38             try:
  39                 file_content = self._extract_content(source)
  40             except Exception as e:
  41                 logger.warning("Could not read %s. Skipping it. Error: %s", source, e)
  42                 continue
  43             try:
  44                 text = extractor.get_content(file_content)
  45             except Exception as conversion_e:  # Consider specifying the expected exception type(s) here
  46                 logger.warning("Failed to extract text from %s. Skipping it. Error: %s", source, conversion_e)
  47                 continue
  48 
  49             document = Document(content=text)
  50             documents.append(document)
  51 
  52         return {"documents": documents}
  53 
  54     def _extract_content(self, source: Union[str, Path, ByteStream]) -> str:
  55         """
  56         Extracts content from the given data source
  57         :param source: The data source to extract content from.
  58         :return: The extracted content.
  59         """
  60         if isinstance(source, (str, Path)):
  61             with open(source) as text_file:
  62                 return text_file.read()
  63         if isinstance(source, ByteStream):
  64             return source.data.decode("utf-8")
  65 
  66         raise ValueError(f"Unsupported source type: {type(source)}")
  67
  ```
  --- 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/preview/components/file_converters/html.py b/haystack/preview/components/file_converters/html.py
  --- a/haystack/preview/components/file_converters/html.py
  +++ b/haystack/preview/components/file_converters/html.py
  @@ -1,6 +1,6 @@
   import logging
  -from typing import List, Union
   from pathlib import Path
  +from typing import Any, Dict, List, Optional, Union
   
   from haystack.preview import Document, component
   from haystack.preview.dataclasses import ByteStream
  @@ -16,6 +16,18 @@
   class HTMLToDocument:
       """
       Converts an HTML file to a Document.
  +
  +    Usage example:
  +    ```python
  +    from haystack.preview.components.file_converters.html import HTMLToDocument
  +
  +    converter = HTMLToDocument()
  +    results = converter.run(sources=["sample.html"])
  +    documents = results["documents"]
  +    print(documents[0].content)
  +    # 'This is a text from the HTML file.'
  +    ```
  +
       """
   
       def __init__(self):
  @@ -25,18 +37,30 @@
           boilerpy3_import.check()
   
       @component.output_types(documents=List[Document])
  -    def run(self, sources: List[Union[str, Path, ByteStream]]):
  +    def run(self, sources: List[Union[str, Path, ByteStream]], meta: Optional[List[Dict[str, Any]]] = None):
           """
           Converts a list of HTML files to Documents.
   
           :param sources: List of HTML file paths or ByteStream objects.
  +        :param meta: Optional list of metadata to attach to the Documents.
  +        The length of the list must match the number of sources. Defaults to `None`.
           :return: List of converted Documents.
           """
  +
           documents = []
  +
  +        # Create metadata placeholders if not provided
  +        if meta:
  +            if len(sources) != len(meta):
  +                raise ValueError("The length of the metadata list must match the number of sources.")
  +        else:
  +            meta = [{}] * len(sources)
  +
           extractor = extractors.ArticleExtractor(raise_on_failure=False)
  -        for source in sources:
  +
  +        for source, metadata in zip(sources, meta):
               try:
  -                file_content = self._extract_content(source)
  +                file_content, extracted_meta = self._extract_content(source)
               except Exception as e:
                   logger.warning("Could not read %s. Skipping it. Error: %s", source, e)
                   continue
  @@ -46,21 +70,25 @@
                   logger.warning("Failed to extract text from %s. Skipping it. Error: %s", source, conversion_e)
                   continue
   
  -            document = Document(content=text)
  +            # Merge metadata received from ByteStream with supplied metadata
  +            if extracted_meta:
  +                # Supplied metadata overwrites metadata from ByteStream for overlapping keys.
  +                metadata = {**extracted_meta, **metadata}
  +            document = Document(content=text, meta=metadata)
               documents.append(document)
   
           return {"documents": documents}
   
  -    def _extract_content(self, source: Union[str, Path, ByteStream]) -> str:
  +    def _extract_content(self, source: Union[str, Path, ByteStream]) -> tuple:
           """
           Extracts content from the given data source
           :param source: The data source to extract content from.
  -        :return: The extracted content.
  +        :return: The extracted content and metadata.
           """
           if isinstance(source, (str, Path)):
               with open(source) as text_file:
  -                return text_file.read()
  +                return (text_file.read(), None)
           if isinstance(source, ByteStream):
  -            return source.data.decode("utf-8")
  +            return (source.data.decode("utf-8"), source.metadata)
   
           raise ValueError(f"Unsupported source type: {type(source)}")
  
verification_info: {"golden_diff": "diff --git a/haystack/preview/components/file_converters/html.py b/haystack/preview/components/file_converters/html.py\n--- a/haystack/preview/components/file_converters/html.py\n+++ b/haystack/preview/components/file_converters/html.py\n@@ -1,6 +1,6 @@\n import logging\n-from typing import List, Union\n from pathlib import Path\n+from typing import Any, Dict, List, Optional, Union\n \n from haystack.preview import Document, component\n from haystack.preview.dataclasses import ByteStream\n@@ -16,6 +16,18 @@\n class HTMLToDocument:\n     \"\"\"\n     Converts an HTML file to a Document.\n+\n+    Usage example:\n+    ```python\n+    from haystack.preview.components.file_converters.html import HTMLToDocument\n+\n+    converter = HTMLToDocument()\n+    results = converter.run(sources=[\"sample.html\"])\n+    documents = results[\"documents\"]\n+    print(documents[0].content)\n+    # 'This is a text from the HTML file.'\n+    ```\n+\n     \"\"\"\n \n     def __init__(self):\n@@ -25,18 +37,30 @@\n         boilerpy3_import.check()\n \n     @component.output_types(documents=List[Document])\n-    def run(self, sources: List[Union[str, Path, ByteStream]]):\n+    def run(self, sources: List[Union[str, Path, ByteStream]], meta: Optional[List[Dict[str, Any]]] = None):\n         \"\"\"\n         Converts a list of HTML files to Documents.\n \n         :param sources: List of HTML file paths or ByteStream objects.\n+        :param meta: Optional list of metadata to attach to the Documents.\n+        The length of the list must match the number of sources. Defaults to `None`.\n         :return: List of converted Documents.\n         \"\"\"\n+\n         documents = []\n+\n+        # Create metadata placeholders if not provided\n+        if meta:\n+            if len(sources) != len(meta):\n+                raise ValueError(\"The length of the metadata list must match the number of sources.\")\n+        else:\n+            meta = [{}] * len(sources)\n+\n         extractor = extractors.ArticleExtractor(raise_on_failure=False)\n-        for source in sources:\n+\n+        for source, metadata in zip(sources, meta):\n             try:\n-                file_content = self._extract_content(source)\n+                file_content, extracted_meta = self._extract_content(source)\n             except Exception as e:\n                 logger.warning(\"Could not read %s. Skipping it. Error: %s\", source, e)\n                 continue\n@@ -46,21 +70,25 @@\n                 logger.warning(\"Failed to extract text from %s. Skipping it. Error: %s\", source, conversion_e)\n                 continue\n \n-            document = Document(content=text)\n+            # Merge metadata received from ByteStream with supplied metadata\n+            if extracted_meta:\n+                # Supplied metadata overwrites metadata from ByteStream for overlapping keys.\n+                metadata = {**extracted_meta, **metadata}\n+            document = Document(content=text, meta=metadata)\n             documents.append(document)\n \n         return {\"documents\": documents}\n \n-    def _extract_content(self, source: Union[str, Path, ByteStream]) -> str:\n+    def _extract_content(self, source: Union[str, Path, ByteStream]) -> tuple:\n         \"\"\"\n         Extracts content from the given data source\n         :param source: The data source to extract content from.\n-        :return: The extracted content.\n+        :return: The extracted content and metadata.\n         \"\"\"\n         if isinstance(source, (str, Path)):\n             with open(source) as text_file:\n-                return text_file.read()\n+                return (text_file.read(), None)\n         if isinstance(source, ByteStream):\n-            return source.data.decode(\"utf-8\")\n+            return (source.data.decode(\"utf-8\"), source.metadata)\n \n         raise ValueError(f\"Unsupported source type: {type(source)}\")\n", "issue": "`HTMLToDocument` to add `ByteStream` metadata to Document \n`HTMLToDocument` converter, when receiving a `ByteStream` from the `LinkContentFetcher` does not add the url to the metadata of the Document. The URL is in the metadata of the ByteStream\r\n\n", "before_files": [{"content": "import logging\nfrom typing import List, Union\nfrom pathlib import Path\n\nfrom haystack.preview import Document, component\nfrom haystack.preview.dataclasses import ByteStream\nfrom haystack.preview.lazy_imports import LazyImport\n\nlogger = logging.getLogger(__name__)\n\nwith LazyImport(\"Run 'pip install boilerpy3'\") as boilerpy3_import:\n    from boilerpy3 import extractors\n\n\n@component\nclass HTMLToDocument:\n    \"\"\"\n    Converts an HTML file to a Document.\n    \"\"\"\n\n    def __init__(self):\n        \"\"\"\n        Initializes the HTMLToDocument component.\n        \"\"\"\n        boilerpy3_import.check()\n\n    @component.output_types(documents=List[Document])\n    def run(self, sources: List[Union[str, Path, ByteStream]]):\n        \"\"\"\n        Converts a list of HTML files to Documents.\n\n        :param sources: List of HTML file paths or ByteStream objects.\n        :return: List of converted Documents.\n        \"\"\"\n        documents = []\n        extractor = extractors.ArticleExtractor(raise_on_failure=False)\n        for source in sources:\n            try:\n                file_content = self._extract_content(source)\n            except Exception as e:\n                logger.warning(\"Could not read %s. Skipping it. Error: %s\", source, e)\n                continue\n            try:\n                text = extractor.get_content(file_content)\n            except Exception as conversion_e:  # Consider specifying the expected exception type(s) here\n                logger.warning(\"Failed to extract text from %s. Skipping it. Error: %s\", source, conversion_e)\n                continue\n\n            document = Document(content=text)\n            documents.append(document)\n\n        return {\"documents\": documents}\n\n    def _extract_content(self, source: Union[str, Path, ByteStream]) -> str:\n        \"\"\"\n        Extracts content from the given data source\n        :param source: The data source to extract content from.\n        :return: The extracted content.\n        \"\"\"\n        if isinstance(source, (str, Path)):\n            with open(source) as text_file:\n                return text_file.read()\n        if isinstance(source, ByteStream):\n            return source.data.decode(\"utf-8\")\n\n        raise ValueError(f\"Unsupported source type: {type(source)}\")\n", "path": "haystack/preview/components/file_converters/html.py"}], "after_files": [{"content": "import logging\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Union\n\nfrom haystack.preview import Document, component\nfrom haystack.preview.dataclasses import ByteStream\nfrom haystack.preview.lazy_imports import LazyImport\n\nlogger = logging.getLogger(__name__)\n\nwith LazyImport(\"Run 'pip install boilerpy3'\") as boilerpy3_import:\n    from boilerpy3 import extractors\n\n\n@component\nclass HTMLToDocument:\n    \"\"\"\n    Converts an HTML file to a Document.\n\n    Usage example:\n    ```python\n    from haystack.preview.components.file_converters.html import HTMLToDocument\n\n    converter = HTMLToDocument()\n    results = converter.run(sources=[\"sample.html\"])\n    documents = results[\"documents\"]\n    print(documents[0].content)\n    # 'This is a text from the HTML file.'\n    ```\n\n    \"\"\"\n\n    def __init__(self):\n        \"\"\"\n        Initializes the HTMLToDocument component.\n        \"\"\"\n        boilerpy3_import.check()\n\n    @component.output_types(documents=List[Document])\n    def run(self, sources: List[Union[str, Path, ByteStream]], meta: Optional[List[Dict[str, Any]]] = None):\n        \"\"\"\n        Converts a list of HTML files to Documents.\n\n        :param sources: List of HTML file paths or ByteStream objects.\n        :param meta: Optional list of metadata to attach to the Documents.\n        The length of the list must match the number of sources. Defaults to `None`.\n        :return: List of converted Documents.\n        \"\"\"\n\n        documents = []\n\n        # Create metadata placeholders if not provided\n        if meta:\n            if len(sources) != len(meta):\n                raise ValueError(\"The length of the metadata list must match the number of sources.\")\n        else:\n            meta = [{}] * len(sources)\n\n        extractor = extractors.ArticleExtractor(raise_on_failure=False)\n\n        for source, metadata in zip(sources, meta):\n            try:\n                file_content, extracted_meta = self._extract_content(source)\n            except Exception as e:\n                logger.warning(\"Could not read %s. Skipping it. Error: %s\", source, e)\n                continue\n            try:\n                text = extractor.get_content(file_content)\n            except Exception as conversion_e:  # Consider specifying the expected exception type(s) here\n                logger.warning(\"Failed to extract text from %s. Skipping it. Error: %s\", source, conversion_e)\n                continue\n\n            # Merge metadata received from ByteStream with supplied metadata\n            if extracted_meta:\n                # Supplied metadata overwrites metadata from ByteStream for overlapping keys.\n                metadata = {**extracted_meta, **metadata}\n            document = Document(content=text, meta=metadata)\n            documents.append(document)\n\n        return {\"documents\": documents}\n\n    def _extract_content(self, source: Union[str, Path, ByteStream]) -> tuple:\n        \"\"\"\n        Extracts content from the given data source\n        :param source: The data source to extract content from.\n        :return: The extracted content and metadata.\n        \"\"\"\n        if isinstance(source, (str, Path)):\n            with open(source) as text_file:\n                return (text_file.read(), None)\n        if isinstance(source, ByteStream):\n            return (source.data.decode(\"utf-8\"), source.metadata)\n\n        raise ValueError(f\"Unsupported source type: {type(source)}\")\n", "path": "haystack/preview/components/file_converters/html.py"}]}