Repository: deepset-ai/haystack

Issue:
Deserialize - AzureOpenAIGenerator
**Describe the bug**
I am using `haystack-ai==2.1.1`

I create prettry simple pipeline which only use prompt builder than it pass it to azure open ai and serialize it, I am trying to load it from another module but I am failling due to the attached trace back.

you can find a notebook which I am using for creating the pipeline also attached.

**Error message**
```python
Traceback (most recent call last):
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/haystack/core/pipeline/pipeline.py", line 172, in from_dict
    raise PipelineError(
haystack.core.errors.PipelineError: Successfully imported module haystack.components.generators but can't find it in the component registry.This is unexpected and most likely a bug.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 411, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 69, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
    await self.app(scope, receive, send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 278, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 193, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/starlette/concurrency.py", line 42, in run_in_threadpool
    return await anyio.to_thread.run_sync(func, *args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/anyio/to_thread.py", line 56, in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 2144, in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 851, in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/netguru_service/api/v1/chat.py", line 26, in chat
    pipeline.loads(yaml_pipeline)
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/haystack/core/pipeline/pipeline.py", line 234, in loads
    return cls.from_dict(marshaller.unmarshal(data), callbacks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/grabin/projects/netnemo/netguru-service/.venv/lib/python3.12/site-packages/haystack/core/pipeline/pipeline.py", line 177, in from_dict
    raise PipelineError(f"Component '{component_data['type']}' not imported.") from e
haystack.core.errors.PipelineError: Component 'haystack.components.generators.AzureOpenAIGenerator' not imported.
```

**Expected behavior**
I expected the 

**Additional context**
Add any other context about the problem here, like document types / preprocessing steps / settings of reader etc.

**To Reproduce**
Steps to reproduce the behavior `AzureOpenAIGenerator` to be loaded correctly.

**FAQ Check**
- [x] Have you had a look at [our new FAQ page](https://docs.haystack.deepset.ai/docs/faq)? yes

**System:**
 - OS: Mac
 - GPU/CPU: M3 pro
 - Haystack version (commit or version number): 2.1.1
 - DocumentStore:
 - Reader:
 - Retriever:



Discussion:

Resolving patch:
diff --git a/haystack/components/generators/azure.py b/haystack/components/generators/azure.py
--- a/haystack/components/generators/azure.py
+++ b/haystack/components/generators/azure.py
@@ -8,7 +8,7 @@
 # pylint: disable=import-error
 from openai.lib.azure import AzureOpenAI
 
-from haystack import default_from_dict, default_to_dict, logging
+from haystack import component, default_from_dict, default_to_dict, logging
 from haystack.components.generators import OpenAIGenerator
 from haystack.dataclasses import StreamingChunk
 from haystack.utils import Secret, deserialize_callable, deserialize_secrets_inplace, serialize_callable
@@ -16,6 +16,7 @@
 logger = logging.getLogger(__name__)
 
 
+@component
 class AzureOpenAIGenerator(OpenAIGenerator):
     """
     A Generator component that uses OpenAI's large language models (LLMs) on Azure to generate text.
diff --git a/haystack/components/generators/chat/azure.py b/haystack/components/generators/chat/azure.py
--- a/haystack/components/generators/chat/azure.py
+++ b/haystack/components/generators/chat/azure.py
@@ -8,7 +8,7 @@
 # pylint: disable=import-error
 from openai.lib.azure import AzureOpenAI
 
-from haystack import default_from_dict, default_to_dict, logging
+from haystack import component, default_from_dict, default_to_dict, logging
 from haystack.components.generators.chat import OpenAIChatGenerator
 from haystack.dataclasses import StreamingChunk
 from haystack.utils import Secret, deserialize_callable, deserialize_secrets_inplace, serialize_callable
@@ -16,6 +16,7 @@
 logger = logging.getLogger(__name__)
 
 
+@component
 class AzureOpenAIChatGenerator(OpenAIChatGenerator):
     """
     A Chat Generator component that uses the Azure OpenAI API to generate text.


Test patch:
diff --git a/test/components/generators/chat/test_azure.py b/test/components/generators/chat/test_azure.py
--- a/test/components/generators/chat/test_azure.py
+++ b/test/components/generators/chat/test_azure.py
@@ -6,6 +6,7 @@
 import pytest
 from openai import OpenAIError
 
+from haystack import Pipeline
 from haystack.components.generators.chat import AzureOpenAIChatGenerator
 from haystack.components.generators.utils import print_streaming_chunk
 from haystack.dataclasses import ChatMessage
@@ -80,6 +81,15 @@ def test_to_dict_with_parameters(self, monkeypatch):
             },
         }
 
+    def test_pipeline_serialization_deserialization(self, tmp_path, monkeypatch):
+        monkeypatch.setenv("AZURE_OPENAI_API_KEY", "test-api-key")
+        generator = AzureOpenAIChatGenerator(azure_endpoint="some-non-existing-endpoint")
+        p = Pipeline()
+        p.add_component(instance=generator, name="generator")
+        p_str = p.dumps()
+        q = Pipeline.loads(p_str)
+        assert p.to_dict() == q.to_dict(), "Pipeline serialization/deserialization w/ AzureOpenAIChatGenerator failed."
+
     @pytest.mark.integration
     @pytest.mark.skipif(
         not os.environ.get("AZURE_OPENAI_API_KEY", None) and not os.environ.get("AZURE_OPENAI_ENDPOINT", None),
diff --git a/test/components/generators/test_azure.py b/test/components/generators/test_azure.py
--- a/test/components/generators/test_azure.py
+++ b/test/components/generators/test_azure.py
@@ -2,6 +2,8 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 import os
+
+from haystack import Pipeline
 from haystack.utils.auth import Secret
 
 import pytest
@@ -83,6 +85,15 @@ def test_to_dict_with_parameters(self, monkeypatch):
             },
         }
 
+    def test_pipeline_serialization_deserialization(self, tmp_path, monkeypatch):
+        monkeypatch.setenv("AZURE_OPENAI_API_KEY", "test-api-key")
+        generator = AzureOpenAIGenerator(azure_endpoint="some-non-existing-endpoint")
+        p = Pipeline()
+        p.add_component(instance=generator, name="generator")
+        p_str = p.dumps()
+        q = Pipeline.loads(p_str)
+        assert p.to_dict() == q.to_dict(), "Pipeline serialization/deserialization with AzureOpenAIGenerator failed."
+
     @pytest.mark.integration
     @pytest.mark.skipif(
         not os.environ.get("AZURE_OPENAI_API_KEY", None) and not os.environ.get("AZURE_OPENAI_ENDPOINT", None),