Skip to content

Commit e17d0c4

Browse files
authored
chore: deprecate to_openai_format and create similar utility functions (#8146)
* deprecate and add new specific functions * reno
1 parent c50a605 commit e17d0c4

File tree

8 files changed

+98
-4
lines changed

8 files changed

+98
-4
lines changed

haystack/components/generators/chat/hugging_face_api.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,22 @@
1818
logger = logging.getLogger(__name__)
1919

2020

21+
def _convert_message_to_hfapi_format(message: ChatMessage) -> Dict[str, str]:
22+
"""
23+
Convert a message to the format expected by Hugging Face APIs.
24+
25+
:returns: A dictionary with the following keys:
26+
- `role`
27+
- `content`
28+
- `name` (optional)
29+
"""
30+
formatted_msg = {"role": message.role.value, "content": message.content}
31+
if message.name:
32+
formatted_msg["name"] = message.name
33+
34+
return formatted_msg
35+
36+
2137
@component
2238
class HuggingFaceAPIChatGenerator:
2339
"""
@@ -204,7 +220,7 @@ def run(self, messages: List[ChatMessage], generation_kwargs: Optional[Dict[str,
204220
# update generation kwargs by merging with the default ones
205221
generation_kwargs = {**self.generation_kwargs, **(generation_kwargs or {})}
206222

207-
formatted_messages = [m.to_openai_format() for m in messages]
223+
formatted_messages = [_convert_message_to_hfapi_format(message) for message in messages]
208224

209225
if self.streaming_callback:
210226
return self._run_streaming(formatted_messages, generation_kwargs)

haystack/components/generators/chat/openai.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from openai.types.chat.chat_completion_chunk import Choice as ChunkChoice
1414

1515
from haystack import component, default_from_dict, default_to_dict, logging
16+
from haystack.components.generators.openai_utils import _convert_message_to_openai_format
1617
from haystack.dataclasses import ChatMessage, StreamingChunk
1718
from haystack.utils import Secret, deserialize_callable, deserialize_secrets_inplace, serialize_callable
1819

@@ -204,7 +205,7 @@ def run(
204205
streaming_callback = streaming_callback or self.streaming_callback
205206

206207
# adapt ChatMessage(s) to the format expected by the OpenAI API
207-
openai_formatted_messages = [message.to_openai_format() for message in messages]
208+
openai_formatted_messages = [_convert_message_to_openai_format(message) for message in messages]
208209

209210
chat_completion: Union[Stream[ChatCompletionChunk], ChatCompletion] = self.client.chat.completions.create(
210211
model=self.model,

haystack/components/generators/openai.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from openai.types.chat import ChatCompletion, ChatCompletionChunk
1010

1111
from haystack import component, default_from_dict, default_to_dict, logging
12+
from haystack.components.generators.openai_utils import _convert_message_to_openai_format
1213
from haystack.dataclasses import ChatMessage, StreamingChunk
1314
from haystack.utils import Secret, deserialize_callable, deserialize_secrets_inplace, serialize_callable
1415

@@ -200,7 +201,7 @@ def run(
200201
streaming_callback = streaming_callback or self.streaming_callback
201202

202203
# adapt ChatMessage(s) to the format expected by the OpenAI API
203-
openai_formatted_messages = [message.to_openai_format() for message in messages]
204+
openai_formatted_messages = [_convert_message_to_openai_format(message) for message in messages]
204205

205206
completion: Union[Stream[ChatCompletionChunk], ChatCompletion] = self.client.chat.completions.create(
206207
model=self.model,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# SPDX-FileCopyrightText: 2022-present deepset GmbH <[email protected]>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from typing import Dict
6+
7+
from haystack.dataclasses import ChatMessage
8+
9+
10+
def _convert_message_to_openai_format(message: ChatMessage) -> Dict[str, str]:
11+
"""
12+
Convert a message to the format expected by OpenAI's Chat API.
13+
14+
See the [API reference](https://platform.openai.com/docs/api-reference/chat/create) for details.
15+
16+
:returns: A dictionary with the following key:
17+
- `role`
18+
- `content`
19+
- `name` (optional)
20+
"""
21+
openai_msg = {"role": message.role.value, "content": message.content}
22+
if message.name:
23+
openai_msg["name"] = message.name
24+
25+
return openai_msg

haystack/dataclasses/chat_message.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from dataclasses import asdict, dataclass, field
66
from enum import Enum
77
from typing import Any, Dict, Optional
8+
from warnings import warn
89

910

1011
class ChatRole(str, Enum):
@@ -43,6 +44,8 @@ def to_openai_format(self) -> Dict[str, Any]:
4344
- `content`
4445
- `name` (optional)
4546
"""
47+
warn("The `to_openai_format` method is deprecated and will be removed in Haystack 2.5.0.", DeprecationWarning)
48+
4649
msg = {"role": self.role.value, "content": self.content}
4750
if self.name:
4851
msg["name"] = self.name
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
deprecations:
3+
- |
4+
Deprecate the method `to_openai_format` of the `ChatMessage` dataclass.
5+
This method was never intended to be public and was only used internally.
6+
Now, each Chat Generator will know internally how to convert the messages to
7+
the format of their specific provider.

test/components/generators/chat/test_hugging_face_api.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
)
1616
from huggingface_hub.utils import RepositoryNotFoundError
1717

18-
from haystack.components.generators.chat import HuggingFaceAPIChatGenerator
18+
from haystack.components.generators.chat.hugging_face_api import (
19+
HuggingFaceAPIChatGenerator,
20+
_convert_message_to_hfapi_format,
21+
)
1922
from haystack.dataclasses import ChatMessage, StreamingChunk
2023
from haystack.utils.auth import Secret
2124
from haystack.utils.hf import HFGenerationAPIType
@@ -58,6 +61,21 @@ def streaming_callback_handler(x):
5861
return x
5962

6063

64+
def test_convert_message_to_hfapi_format():
65+
message = ChatMessage.from_system("You are good assistant")
66+
assert _convert_message_to_hfapi_format(message) == {"role": "system", "content": "You are good assistant"}
67+
68+
message = ChatMessage.from_user("I have a question")
69+
assert _convert_message_to_hfapi_format(message) == {"role": "user", "content": "I have a question"}
70+
71+
message = ChatMessage.from_function("Function call", "function_name")
72+
assert _convert_message_to_hfapi_format(message) == {
73+
"role": "function",
74+
"content": "Function call",
75+
"name": "function_name",
76+
}
77+
78+
6179
class TestHuggingFaceAPIGenerator:
6280
def test_init_invalid_api_type(self):
6381
with pytest.raises(ValueError):
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-FileCopyrightText: 2022-present deepset GmbH <[email protected]>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import pytest
6+
7+
from haystack.dataclasses import ChatMessage
8+
from haystack.components.generators.openai_utils import _convert_message_to_openai_format
9+
10+
11+
def test_convert_message_to_openai_format():
12+
message = ChatMessage.from_system("You are good assistant")
13+
assert _convert_message_to_openai_format(message) == {"role": "system", "content": "You are good assistant"}
14+
15+
message = ChatMessage.from_user("I have a question")
16+
assert _convert_message_to_openai_format(message) == {"role": "user", "content": "I have a question"}
17+
18+
message = ChatMessage.from_function("Function call", "function_name")
19+
assert _convert_message_to_openai_format(message) == {
20+
"role": "function",
21+
"content": "Function call",
22+
"name": "function_name",
23+
}

0 commit comments

Comments
 (0)