We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add `max_retries` and `timeout` params to all `AzureOpenAI` classes
**Is your feature request related to a problem? Please describe.**

Currently all `OpenAI` related classes (e.g. `OpenAIDocumentEmbedder`, `OpenAIChatGenerator`) can be initialised by setting `max_retries` and `timeout` params.

The corresponding `AzureOpenAI` don't always have the same params.

**Describe the solution you'd like**

It would be nice to have these params in the `AzureOpenAI` classes

**Describe alternatives you've considered**

Subclass `AzureOpenAI` and create custom components.

**Additional context**

cc @anakin87 :)

--- 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/generators/azure.py`
Content:
```
1 # SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
2 #
3 # SPDX-License-Identifier: Apache-2.0
4 
5 import os
6 from typing import Any, Callable, Dict, Optional
7 
8 # pylint: disable=import-error
9 from openai.lib.azure import AzureOpenAI
10 
11 from haystack import component, default_from_dict, default_to_dict, logging
12 from haystack.components.generators import OpenAIGenerator
13 from haystack.dataclasses import StreamingChunk
14 from haystack.utils import Secret, deserialize_callable, deserialize_secrets_inplace, serialize_callable
15 
16 logger = logging.getLogger(__name__)
17 
18 
19 @component
20 class AzureOpenAIGenerator(OpenAIGenerator):
21     """
22     A Generator component that uses OpenAI's large language models (LLMs) on Azure to generate text.
23 
24     It supports gpt-4 and gpt-3.5-turbo family of models.
25 
26     Users can pass any text generation parameters valid for the `openai.ChatCompletion.create` method
27     directly to this component via the `**generation_kwargs` parameter in __init__ or the `**generation_kwargs`
28     parameter in `run` method.
29 
30     For more details on OpenAI models deployed on Azure, refer to the Microsoft
31     [documentation](https://learn.microsoft.com/en-us/azure/ai-services/openai/).
32 
33     Usage example:
34     ```python
35     from haystack.components.generators import AzureOpenAIGenerator
36     from haystack.utils import Secret
37     client = AzureOpenAIGenerator(
38         azure_endpoint="<Your Azure endpoint e.g. `https://your-company.azure.openai.com/>",
39         api_key=Secret.from_token("<your-api-key>"),
40         azure_deployment="<this a model name, e.g. gpt-35-turbo>")
41     response = client.run("What's Natural Language Processing? Be brief.")
42     print(response)
43     ```
44 
45     ```
46     >> {'replies': ['Natural Language Processing (NLP) is a branch of artificial intelligence that focuses on
47     >> the interaction between computers and human language. It involves enabling computers to understand, interpret,
48     >> and respond to natural human language in a way that is both meaningful and useful.'], 'meta': [{'model':
49     >> 'gpt-3.5-turbo-0613', 'index': 0, 'finish_reason': 'stop', 'usage': {'prompt_tokens': 16,
50     >> 'completion_tokens': 49, 'total_tokens': 65}}]}
51     ```
52     """
53 
54     # pylint: disable=super-init-not-called
55     def __init__(
56         self,
57         azure_endpoint: Optional[str] = None,
58         api_version: Optional[str] = "2023-05-15",
59         azure_deployment: Optional[str] = "gpt-35-turbo",
60         api_key: Optional[Secret] = Secret.from_env_var("AZURE_OPENAI_API_KEY", strict=False),
61         azure_ad_token: Optional[Secret] = Secret.from_env_var("AZURE_OPENAI_AD_TOKEN", strict=False),
62         organization: Optional[str] = None,
63         streaming_callback: Optional[Callable[[StreamingChunk], None]] = None,
64         system_prompt: Optional[str] = None,
65         timeout: Optional[float] = None,
66         generation_kwargs: Optional[Dict[str, Any]] = None,
67     ):
68         """
69         Initialize the Azure OpenAI Generator.
70 
71         :param azure_endpoint: The endpoint of the deployed model, e.g. `https://example-resource.azure.openai.com/`
72         :param api_version: The version of the API to use. Defaults to 2023-05-15
73         :param azure_deployment: The deployment of the model, usually the model name.
74         :param api_key: The API key to use for authentication.
75         :param azure_ad_token: [Azure Active Directory token](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id)
76         :param organization: The Organization ID, defaults to `None`. See
77         [production best practices](https://platform.openai.com/docs/guides/production-best-practices/setting-up-your-organization).
78         :param streaming_callback: A callback function that is called when a new token is received from the stream.
79             The callback function accepts StreamingChunk as an argument.
80         :param system_prompt: The prompt to use for the system. If not provided, the system prompt will be
81         :param timeout: The timeout to be passed to the underlying `AzureOpenAI` client.
82         :param generation_kwargs: Other parameters to use for the model. These parameters are all sent directly to
83             the OpenAI endpoint. See OpenAI [documentation](https://platform.openai.com/docs/api-reference/chat) for
84             more details.
85             Some of the supported parameters:
86             - `max_tokens`: The maximum number of tokens the output text can have.
87             - `temperature`: What sampling temperature to use. Higher values mean the model will take more risks.
88                 Try 0.9 for more creative applications and 0 (argmax sampling) for ones with a well-defined answer.
89             - `top_p`: An alternative to sampling with temperature, called nucleus sampling, where the model
90                 considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens
91                 comprising the top 10% probability mass are considered.
92             - `n`: How many completions to generate for each prompt. For example, if the LLM gets 3 prompts and n is 2,
93                 it will generate two completions for each of the three prompts, ending up with 6 completions in total.
94             - `stop`: One or more sequences after which the LLM should stop generating tokens.
95             - `presence_penalty`: What penalty to apply if a token is already present at all. Bigger values mean
96                 the model will be less likely to repeat the same token in the text.
97             - `frequency_penalty`: What penalty to apply if a token has already been generated in the text.
98                 Bigger values mean the model will be less likely to repeat the same token in the text.
99             - `logit_bias`: Add a logit bias to specific tokens. The keys of the dictionary are tokens, and the
100                 values are the bias to add to that token.
101         """
102         # We intentionally do not call super().__init__ here because we only need to instantiate the client to interact
103         # with the API.
104 
105         # Why is this here?
106         # AzureOpenAI init is forcing us to use an init method that takes either base_url or azure_endpoint as not
107         # None init parameters. This way we accommodate the use case where env var AZURE_OPENAI_ENDPOINT is set instead
108         # of passing it as a parameter.
109         azure_endpoint = azure_endpoint or os.environ.get("AZURE_OPENAI_ENDPOINT")
110         if not azure_endpoint:
111             raise ValueError("Please provide an Azure endpoint or set the environment variable AZURE_OPENAI_ENDPOINT.")
112 
113         if api_key is None and azure_ad_token is None:
114             raise ValueError("Please provide an API key or an Azure Active Directory token.")
115 
116         # The check above makes mypy incorrectly infer that api_key is never None,
117         # which propagates the incorrect type.
118         self.api_key = api_key  # type: ignore
119         self.azure_ad_token = azure_ad_token
120         self.generation_kwargs = generation_kwargs or {}
121         self.system_prompt = system_prompt
122         self.streaming_callback = streaming_callback
123         self.api_version = api_version
124         self.azure_endpoint = azure_endpoint
125         self.azure_deployment = azure_deployment
126         self.organization = organization
127         self.model: str = azure_deployment or "gpt-35-turbo"
128         self.timeout = timeout
129 
130         self.client = AzureOpenAI(
131             api_version=api_version,
132             azure_endpoint=azure_endpoint,
133             azure_deployment=azure_deployment,
134             api_key=api_key.resolve_value() if api_key is not None else None,
135             azure_ad_token=azure_ad_token.resolve_value() if azure_ad_token is not None else None,
136             organization=organization,
137             timeout=timeout,
138         )
139 
140     def to_dict(self) -> Dict[str, Any]:
141         """
142         Serialize this component to a dictionary.
143 
144         :returns:
145             The serialized component as a dictionary.
146         """
147         callback_name = serialize_callable(self.streaming_callback) if self.streaming_callback else None
148         return default_to_dict(
149             self,
150             azure_endpoint=self.azure_endpoint,
151             azure_deployment=self.azure_deployment,
152             organization=self.organization,
153             api_version=self.api_version,
154             streaming_callback=callback_name,
155             generation_kwargs=self.generation_kwargs,
156             system_prompt=self.system_prompt,
157             api_key=self.api_key.to_dict() if self.api_key is not None else None,
158             azure_ad_token=self.azure_ad_token.to_dict() if self.azure_ad_token is not None else None,
159             timeout=self.timeout,
160         )
161 
162     @classmethod
163     def from_dict(cls, data: Dict[str, Any]) -> "AzureOpenAIGenerator":
164         """
165         Deserialize this component from a dictionary.
166 
167         :param data:
168             The dictionary representation of this component.
169         :returns:
170             The deserialized component instance.
171         """
172         deserialize_secrets_inplace(data["init_parameters"], keys=["api_key", "azure_ad_token"])
173         init_params = data.get("init_parameters", {})
174         serialized_callback_handler = init_params.get("streaming_callback")
175         if serialized_callback_handler:
176             data["init_parameters"]["streaming_callback"] = deserialize_callable(serialized_callback_handler)
177         return default_from_dict(cls, data)
178
```
--- 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/generators/azure.py b/haystack/components/generators/azure.py
--- a/haystack/components/generators/azure.py
+++ b/haystack/components/generators/azure.py
@@ -63,6 +63,7 @@
         streaming_callback: Optional[Callable[[StreamingChunk], None]] = None,
         system_prompt: Optional[str] = None,
         timeout: Optional[float] = None,
+        max_retries: Optional[int] = None,
         generation_kwargs: Optional[Dict[str, Any]] = None,
     ):
         """
@@ -78,7 +79,10 @@
         :param streaming_callback: A callback function that is called when a new token is received from the stream.
             The callback function accepts StreamingChunk as an argument.
         :param system_prompt: The prompt to use for the system. If not provided, the system prompt will be
-        :param timeout: The timeout to be passed to the underlying `AzureOpenAI` client.
+        :param timeout: The timeout to be passed to the underlying `AzureOpenAI` client, if not set it is
+            inferred from the `OPENAI_TIMEOUT` environment variable or set to 30.
+        :param max_retries: Maximum retries to establish contact with AzureOpenAI if it returns an internal error,
+            if not set it is inferred from the `OPENAI_MAX_RETRIES` environment variable or set to 5.
         :param generation_kwargs: Other parameters to use for the model. These parameters are all sent directly to
             the OpenAI endpoint. See OpenAI [documentation](https://platform.openai.com/docs/api-reference/chat) for
             more details.
@@ -125,7 +129,8 @@
         self.azure_deployment = azure_deployment
         self.organization = organization
         self.model: str = azure_deployment or "gpt-35-turbo"
-        self.timeout = timeout
+        self.timeout = timeout or float(os.environ.get("OPENAI_TIMEOUT", 30.0))
+        self.max_retries = max_retries or int(os.environ.get("OPENAI_MAX_RETRIES", 5))
 
         self.client = AzureOpenAI(
             api_version=api_version,
@@ -134,7 +139,8 @@
             api_key=api_key.resolve_value() if api_key is not None else None,
             azure_ad_token=azure_ad_token.resolve_value() if azure_ad_token is not None else None,
             organization=organization,
-            timeout=timeout,
+            timeout=self.timeout,
+            max_retries=self.max_retries,
         )
 
     def to_dict(self) -> Dict[str, Any]:
@@ -157,6 +163,7 @@
             api_key=self.api_key.to_dict() if self.api_key is not None else None,
             azure_ad_token=self.azure_ad_token.to_dict() if self.azure_ad_token is not None else None,
             timeout=self.timeout,
+            max_retries=self.max_retries,
         )
 
     @classmethod

{"golden_diff": "diff --git a/haystack/components/generators/azure.py b/haystack/components/generators/azure.py\n--- a/haystack/components/generators/azure.py\n+++ b/haystack/components/generators/azure.py\n@@ -63,6 +63,7 @@\n         streaming_callback: Optional[Callable[[StreamingChunk], None]] = None,\n         system_prompt: Optional[str] = None,\n         timeout: Optional[float] = None,\n+        max_retries: Optional[int] = None,\n         generation_kwargs: Optional[Dict[str, Any]] = None,\n     ):\n         \"\"\"\n@@ -78,7 +79,10 @@\n         :param streaming_callback: A callback function that is called when a new token is received from the stream.\n             The callback function accepts StreamingChunk as an argument.\n         :param system_prompt: The prompt to use for the system. If not provided, the system prompt will be\n-        :param timeout: The timeout to be passed to the underlying `AzureOpenAI` client.\n+        :param timeout: The timeout to be passed to the underlying `AzureOpenAI` client, if not set it is\n+            inferred from the `OPENAI_TIMEOUT` environment variable or set to 30.\n+        :param max_retries: Maximum retries to establish contact with AzureOpenAI if it returns an internal error,\n+            if not set it is inferred from the `OPENAI_MAX_RETRIES` environment variable or set to 5.\n         :param generation_kwargs: Other parameters to use for the model. These parameters are all sent directly to\n             the OpenAI endpoint. See OpenAI [documentation](https://platform.openai.com/docs/api-reference/chat) for\n             more details.\n@@ -125,7 +129,8 @@\n         self.azure_deployment = azure_deployment\n         self.organization = organization\n         self.model: str = azure_deployment or \"gpt-35-turbo\"\n-        self.timeout = timeout\n+        self.timeout = timeout or float(os.environ.get(\"OPENAI_TIMEOUT\", 30.0))\n+        self.max_retries = max_retries or int(os.environ.get(\"OPENAI_MAX_RETRIES\", 5))\n \n         self.client = AzureOpenAI(\n             api_version=api_version,\n@@ -134,7 +139,8 @@\n             api_key=api_key.resolve_value() if api_key is not None else None,\n             azure_ad_token=azure_ad_token.resolve_value() if azure_ad_token is not None else None,\n             organization=organization,\n-            timeout=timeout,\n+            timeout=self.timeout,\n+            max_retries=self.max_retries,\n         )\n \n     def to_dict(self) -> Dict[str, Any]:\n@@ -157,6 +163,7 @@\n             api_key=self.api_key.to_dict() if self.api_key is not None else None,\n             azure_ad_token=self.azure_ad_token.to_dict() if self.azure_ad_token is not None else None,\n             timeout=self.timeout,\n+            max_retries=self.max_retries,\n         )\n \n     @classmethod\n", "issue": "Add `max_retries` and `timeout` params to all `AzureOpenAI` classes\n**Is your feature request related to a problem? Please describe.**\r\n\r\nCurrently all `OpenAI` related classes (e.g. `OpenAIDocumentEmbedder`, `OpenAIChatGenerator`) can be initialised by setting `max_retries` and `timeout` params.\r\n\r\nThe corresponding `AzureOpenAI` don't always have the same params.\r\n\r\n**Describe the solution you'd like**\r\n\r\nIt would be nice to have these params in the `AzureOpenAI` classes\r\n\r\n**Describe alternatives you've considered**\r\n\r\nSubclass `AzureOpenAI` and create custom components.\r\n\r\n**Additional context**\r\n\r\ncc @anakin87 :)\n", "before_files": [{"content": "# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>\n#\n# SPDX-License-Identifier: Apache-2.0\n\nimport os\nfrom typing import Any, Callable, Dict, Optional\n\n# pylint: disable=import-error\nfrom openai.lib.azure import AzureOpenAI\n\nfrom haystack import component, default_from_dict, default_to_dict, logging\nfrom haystack.components.generators import OpenAIGenerator\nfrom haystack.dataclasses import StreamingChunk\nfrom haystack.utils import Secret, deserialize_callable, deserialize_secrets_inplace, serialize_callable\n\nlogger = logging.getLogger(__name__)\n\n\n@component\nclass AzureOpenAIGenerator(OpenAIGenerator):\n    \"\"\"\n    A Generator component that uses OpenAI's large language models (LLMs) on Azure to generate text.\n\n    It supports gpt-4 and gpt-3.5-turbo family of models.\n\n    Users can pass any text generation parameters valid for the `openai.ChatCompletion.create` method\n    directly to this component via the `**generation_kwargs` parameter in __init__ or the `**generation_kwargs`\n    parameter in `run` method.\n\n    For more details on OpenAI models deployed on Azure, refer to the Microsoft\n    [documentation](https://learn.microsoft.com/en-us/azure/ai-services/openai/).\n\n    Usage example:\n    ```python\n    from haystack.components.generators import AzureOpenAIGenerator\n    from haystack.utils import Secret\n    client = AzureOpenAIGenerator(\n        azure_endpoint=\"<Your Azure endpoint e.g. `https://your-company.azure.openai.com/>\",\n        api_key=Secret.from_token(\"<your-api-key>\"),\n        azure_deployment=\"<this a model name, e.g. gpt-35-turbo>\")\n    response = client.run(\"What's Natural Language Processing? Be brief.\")\n    print(response)\n    ```\n\n    ```\n    >> {'replies': ['Natural Language Processing (NLP) is a branch of artificial intelligence that focuses on\n    >> the interaction between computers and human language. It involves enabling computers to understand, interpret,\n    >> and respond to natural human language in a way that is both meaningful and useful.'], 'meta': [{'model':\n    >> 'gpt-3.5-turbo-0613', 'index': 0, 'finish_reason': 'stop', 'usage': {'prompt_tokens': 16,\n    >> 'completion_tokens': 49, 'total_tokens': 65}}]}\n    ```\n    \"\"\"\n\n    # pylint: disable=super-init-not-called\n    def __init__(\n        self,\n        azure_endpoint: Optional[str] = None,\n        api_version: Optional[str] = \"2023-05-15\",\n        azure_deployment: Optional[str] = \"gpt-35-turbo\",\n        api_key: Optional[Secret] = Secret.from_env_var(\"AZURE_OPENAI_API_KEY\", strict=False),\n        azure_ad_token: Optional[Secret] = Secret.from_env_var(\"AZURE_OPENAI_AD_TOKEN\", strict=False),\n        organization: Optional[str] = None,\n        streaming_callback: Optional[Callable[[StreamingChunk], None]] = None,\n        system_prompt: Optional[str] = None,\n        timeout: Optional[float] = None,\n        generation_kwargs: Optional[Dict[str, Any]] = None,\n    ):\n        \"\"\"\n        Initialize the Azure OpenAI Generator.\n\n        :param azure_endpoint: The endpoint of the deployed model, e.g. `https://example-resource.azure.openai.com/`\n        :param api_version: The version of the API to use. Defaults to 2023-05-15\n        :param azure_deployment: The deployment of the model, usually the model name.\n        :param api_key: The API key to use for authentication.\n        :param azure_ad_token: [Azure Active Directory token](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id)\n        :param organization: The Organization ID, defaults to `None`. See\n        [production best practices](https://platform.openai.com/docs/guides/production-best-practices/setting-up-your-organization).\n        :param streaming_callback: A callback function that is called when a new token is received from the stream.\n            The callback function accepts StreamingChunk as an argument.\n        :param system_prompt: The prompt to use for the system. If not provided, the system prompt will be\n        :param timeout: The timeout to be passed to the underlying `AzureOpenAI` client.\n        :param generation_kwargs: Other parameters to use for the model. These parameters are all sent directly to\n            the OpenAI endpoint. See OpenAI [documentation](https://platform.openai.com/docs/api-reference/chat) for\n            more details.\n            Some of the supported parameters:\n            - `max_tokens`: The maximum number of tokens the output text can have.\n            - `temperature`: What sampling temperature to use. Higher values mean the model will take more risks.\n                Try 0.9 for more creative applications and 0 (argmax sampling) for ones with a well-defined answer.\n            - `top_p`: An alternative to sampling with temperature, called nucleus sampling, where the model\n                considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens\n                comprising the top 10% probability mass are considered.\n            - `n`: How many completions to generate for each prompt. For example, if the LLM gets 3 prompts and n is 2,\n                it will generate two completions for each of the three prompts, ending up with 6 completions in total.\n            - `stop`: One or more sequences after which the LLM should stop generating tokens.\n            - `presence_penalty`: What penalty to apply if a token is already present at all. Bigger values mean\n                the model will be less likely to repeat the same token in the text.\n            - `frequency_penalty`: What penalty to apply if a token has already been generated in the text.\n                Bigger values mean the model will be less likely to repeat the same token in the text.\n            - `logit_bias`: Add a logit bias to specific tokens. The keys of the dictionary are tokens, and the\n                values are the bias to add to that token.\n        \"\"\"\n        # We intentionally do not call super().__init__ here because we only need to instantiate the client to interact\n        # with the API.\n\n        # Why is this here?\n        # AzureOpenAI init is forcing us to use an init method that takes either base_url or azure_endpoint as not\n        # None init parameters. This way we accommodate the use case where env var AZURE_OPENAI_ENDPOINT is set instead\n        # of passing it as a parameter.\n        azure_endpoint = azure_endpoint or os.environ.get(\"AZURE_OPENAI_ENDPOINT\")\n        if not azure_endpoint:\n            raise ValueError(\"Please provide an Azure endpoint or set the environment variable AZURE_OPENAI_ENDPOINT.\")\n\n        if api_key is None and azure_ad_token is None:\n            raise ValueError(\"Please provide an API key or an Azure Active Directory token.\")\n\n        # The check above makes mypy incorrectly infer that api_key is never None,\n        # which propagates the incorrect type.\n        self.api_key = api_key  # type: ignore\n        self.azure_ad_token = azure_ad_token\n        self.generation_kwargs = generation_kwargs or {}\n        self.system_prompt = system_prompt\n        self.streaming_callback = streaming_callback\n        self.api_version = api_version\n        self.azure_endpoint = azure_endpoint\n        self.azure_deployment = azure_deployment\n        self.organization = organization\n        self.model: str = azure_deployment or \"gpt-35-turbo\"\n        self.timeout = timeout\n\n        self.client = AzureOpenAI(\n            api_version=api_version,\n            azure_endpoint=azure_endpoint,\n            azure_deployment=azure_deployment,\n            api_key=api_key.resolve_value() if api_key is not None else None,\n            azure_ad_token=azure_ad_token.resolve_value() if azure_ad_token is not None else None,\n            organization=organization,\n            timeout=timeout,\n        )\n\n    def to_dict(self) -> Dict[str, Any]:\n        \"\"\"\n        Serialize this component to a dictionary.\n\n        :returns:\n            The serialized component as a dictionary.\n        \"\"\"\n        callback_name = serialize_callable(self.streaming_callback) if self.streaming_callback else None\n        return default_to_dict(\n            self,\n            azure_endpoint=self.azure_endpoint,\n            azure_deployment=self.azure_deployment,\n            organization=self.organization,\n            api_version=self.api_version,\n            streaming_callback=callback_name,\n            generation_kwargs=self.generation_kwargs,\n            system_prompt=self.system_prompt,\n            api_key=self.api_key.to_dict() if self.api_key is not None else None,\n            azure_ad_token=self.azure_ad_token.to_dict() if self.azure_ad_token is not None else None,\n            timeout=self.timeout,\n        )\n\n    @classmethod\n    def from_dict(cls, data: Dict[str, Any]) -> \"AzureOpenAIGenerator\":\n        \"\"\"\n        Deserialize this component from a dictionary.\n\n        :param data:\n            The dictionary representation of this component.\n        :returns:\n            The deserialized component instance.\n        \"\"\"\n        deserialize_secrets_inplace(data[\"init_parameters\"], keys=[\"api_key\", \"azure_ad_token\"])\n        init_params = data.get(\"init_parameters\", {})\n        serialized_callback_handler = init_params.get(\"streaming_callback\")\n        if serialized_callback_handler:\n            data[\"init_parameters\"][\"streaming_callback\"] = deserialize_callable(serialized_callback_handler)\n        return default_from_dict(cls, data)\n", "path": "haystack/components/generators/azure.py"}], "after_files": [{"content": "# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>\n#\n# SPDX-License-Identifier: Apache-2.0\n\nimport os\nfrom typing import Any, Callable, Dict, Optional\n\n# pylint: disable=import-error\nfrom openai.lib.azure import AzureOpenAI\n\nfrom haystack import component, default_from_dict, default_to_dict, logging\nfrom haystack.components.generators import OpenAIGenerator\nfrom haystack.dataclasses import StreamingChunk\nfrom haystack.utils import Secret, deserialize_callable, deserialize_secrets_inplace, serialize_callable\n\nlogger = logging.getLogger(__name__)\n\n\n@component\nclass AzureOpenAIGenerator(OpenAIGenerator):\n    \"\"\"\n    A Generator component that uses OpenAI's large language models (LLMs) on Azure to generate text.\n\n    It supports gpt-4 and gpt-3.5-turbo family of models.\n\n    Users can pass any text generation parameters valid for the `openai.ChatCompletion.create` method\n    directly to this component via the `**generation_kwargs` parameter in __init__ or the `**generation_kwargs`\n    parameter in `run` method.\n\n    For more details on OpenAI models deployed on Azure, refer to the Microsoft\n    [documentation](https://learn.microsoft.com/en-us/azure/ai-services/openai/).\n\n    Usage example:\n    ```python\n    from haystack.components.generators import AzureOpenAIGenerator\n    from haystack.utils import Secret\n    client = AzureOpenAIGenerator(\n        azure_endpoint=\"<Your Azure endpoint e.g. `https://your-company.azure.openai.com/>\",\n        api_key=Secret.from_token(\"<your-api-key>\"),\n        azure_deployment=\"<this a model name, e.g. gpt-35-turbo>\")\n    response = client.run(\"What's Natural Language Processing? Be brief.\")\n    print(response)\n    ```\n\n    ```\n    >> {'replies': ['Natural Language Processing (NLP) is a branch of artificial intelligence that focuses on\n    >> the interaction between computers and human language. It involves enabling computers to understand, interpret,\n    >> and respond to natural human language in a way that is both meaningful and useful.'], 'meta': [{'model':\n    >> 'gpt-3.5-turbo-0613', 'index': 0, 'finish_reason': 'stop', 'usage': {'prompt_tokens': 16,\n    >> 'completion_tokens': 49, 'total_tokens': 65}}]}\n    ```\n    \"\"\"\n\n    # pylint: disable=super-init-not-called\n    def __init__(\n        self,\n        azure_endpoint: Optional[str] = None,\n        api_version: Optional[str] = \"2023-05-15\",\n        azure_deployment: Optional[str] = \"gpt-35-turbo\",\n        api_key: Optional[Secret] = Secret.from_env_var(\"AZURE_OPENAI_API_KEY\", strict=False),\n        azure_ad_token: Optional[Secret] = Secret.from_env_var(\"AZURE_OPENAI_AD_TOKEN\", strict=False),\n        organization: Optional[str] = None,\n        streaming_callback: Optional[Callable[[StreamingChunk], None]] = None,\n        system_prompt: Optional[str] = None,\n        timeout: Optional[float] = None,\n        max_retries: Optional[int] = None,\n        generation_kwargs: Optional[Dict[str, Any]] = None,\n    ):\n        \"\"\"\n        Initialize the Azure OpenAI Generator.\n\n        :param azure_endpoint: The endpoint of the deployed model, e.g. `https://example-resource.azure.openai.com/`\n        :param api_version: The version of the API to use. Defaults to 2023-05-15\n        :param azure_deployment: The deployment of the model, usually the model name.\n        :param api_key: The API key to use for authentication.\n        :param azure_ad_token: [Azure Active Directory token](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id)\n        :param organization: The Organization ID, defaults to `None`. See\n        [production best practices](https://platform.openai.com/docs/guides/production-best-practices/setting-up-your-organization).\n        :param streaming_callback: A callback function that is called when a new token is received from the stream.\n            The callback function accepts StreamingChunk as an argument.\n        :param system_prompt: The prompt to use for the system. If not provided, the system prompt will be\n        :param timeout: The timeout to be passed to the underlying `AzureOpenAI` client, if not set it is\n            inferred from the `OPENAI_TIMEOUT` environment variable or set to 30.\n        :param max_retries: Maximum retries to establish contact with AzureOpenAI if it returns an internal error,\n            if not set it is inferred from the `OPENAI_MAX_RETRIES` environment variable or set to 5.\n        :param generation_kwargs: Other parameters to use for the model. These parameters are all sent directly to\n            the OpenAI endpoint. See OpenAI [documentation](https://platform.openai.com/docs/api-reference/chat) for\n            more details.\n            Some of the supported parameters:\n            - `max_tokens`: The maximum number of tokens the output text can have.\n            - `temperature`: What sampling temperature to use. Higher values mean the model will take more risks.\n                Try 0.9 for more creative applications and 0 (argmax sampling) for ones with a well-defined answer.\n            - `top_p`: An alternative to sampling with temperature, called nucleus sampling, where the model\n                considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens\n                comprising the top 10% probability mass are considered.\n            - `n`: How many completions to generate for each prompt. For example, if the LLM gets 3 prompts and n is 2,\n                it will generate two completions for each of the three prompts, ending up with 6 completions in total.\n            - `stop`: One or more sequences after which the LLM should stop generating tokens.\n            - `presence_penalty`: What penalty to apply if a token is already present at all. Bigger values mean\n                the model will be less likely to repeat the same token in the text.\n            - `frequency_penalty`: What penalty to apply if a token has already been generated in the text.\n                Bigger values mean the model will be less likely to repeat the same token in the text.\n            - `logit_bias`: Add a logit bias to specific tokens. The keys of the dictionary are tokens, and the\n                values are the bias to add to that token.\n        \"\"\"\n        # We intentionally do not call super().__init__ here because we only need to instantiate the client to interact\n        # with the API.\n\n        # Why is this here?\n        # AzureOpenAI init is forcing us to use an init method that takes either base_url or azure_endpoint as not\n        # None init parameters. This way we accommodate the use case where env var AZURE_OPENAI_ENDPOINT is set instead\n        # of passing it as a parameter.\n        azure_endpoint = azure_endpoint or os.environ.get(\"AZURE_OPENAI_ENDPOINT\")\n        if not azure_endpoint:\n            raise ValueError(\"Please provide an Azure endpoint or set the environment variable AZURE_OPENAI_ENDPOINT.\")\n\n        if api_key is None and azure_ad_token is None:\n            raise ValueError(\"Please provide an API key or an Azure Active Directory token.\")\n\n        # The check above makes mypy incorrectly infer that api_key is never None,\n        # which propagates the incorrect type.\n        self.api_key = api_key  # type: ignore\n        self.azure_ad_token = azure_ad_token\n        self.generation_kwargs = generation_kwargs or {}\n        self.system_prompt = system_prompt\n        self.streaming_callback = streaming_callback\n        self.api_version = api_version\n        self.azure_endpoint = azure_endpoint\n        self.azure_deployment = azure_deployment\n        self.organization = organization\n        self.model: str = azure_deployment or \"gpt-35-turbo\"\n        self.timeout = timeout or float(os.environ.get(\"OPENAI_TIMEOUT\", 30.0))\n        self.max_retries = max_retries or int(os.environ.get(\"OPENAI_MAX_RETRIES\", 5))\n\n        self.client = AzureOpenAI(\n            api_version=api_version,\n            azure_endpoint=azure_endpoint,\n            azure_deployment=azure_deployment,\n            api_key=api_key.resolve_value() if api_key is not None else None,\n            azure_ad_token=azure_ad_token.resolve_value() if azure_ad_token is not None else None,\n            organization=organization,\n            timeout=self.timeout,\n            max_retries=self.max_retries,\n        )\n\n    def to_dict(self) -> Dict[str, Any]:\n        \"\"\"\n        Serialize this component to a dictionary.\n\n        :returns:\n            The serialized component as a dictionary.\n        \"\"\"\n        callback_name = serialize_callable(self.streaming_callback) if self.streaming_callback else None\n        return default_to_dict(\n            self,\n            azure_endpoint=self.azure_endpoint,\n            azure_deployment=self.azure_deployment,\n            organization=self.organization,\n            api_version=self.api_version,\n            streaming_callback=callback_name,\n            generation_kwargs=self.generation_kwargs,\n            system_prompt=self.system_prompt,\n            api_key=self.api_key.to_dict() if self.api_key is not None else None,\n            azure_ad_token=self.azure_ad_token.to_dict() if self.azure_ad_token is not None else None,\n            timeout=self.timeout,\n            max_retries=self.max_retries,\n        )\n\n    @classmethod\n    def from_dict(cls, data: Dict[str, Any]) -> \"AzureOpenAIGenerator\":\n        \"\"\"\n        Deserialize this component from a dictionary.\n\n        :param data:\n            The dictionary representation of this component.\n        :returns:\n            The deserialized component instance.\n        \"\"\"\n        deserialize_secrets_inplace(data[\"init_parameters\"], keys=[\"api_key\", \"azure_ad_token\"])\n        init_params = data.get(\"init_parameters\", {})\n        serialized_callback_handler = init_params.get(\"streaming_callback\")\n        if serialized_callback_handler:\n            data[\"init_parameters\"][\"streaming_callback\"] = deserialize_callable(serialized_callback_handler)\n        return default_from_dict(cls, data)\n", "path": "haystack/components/generators/azure.py"}]}