Skip to content

Commit 9a683c9

Browse files
committed
fix(perplexity): address sjrl review comments
- embedders: fix api_base_url default to include /v1 (was hitting https://api.perplexity.ai/embeddings -> 404; correct endpoint is https://api.perplexity.ai/v1/embeddings). This is why the embedder integration tests failed for sjrl. - embedders: add explicit from_dict classmethod on both PerplexityDocumentEmbedder and PerplexityTextEmbedder for correct typing (r3224097561, r3224106489). - chat generator: use generate_qualified_class_name() instead of hardcoded class path in to_dict (r3224126336); drop redundant data['type'] override in from_dict (r3224130257); drop unused module-level path constants (r3224143875). - websearch: drop unreachable 'client failed to initialize' RuntimeError branches in run / run_async — warm_up always runs first (r3224158183, r3224160907). - websearch: tighten return-type hint on run / run_async to dict[str, list[Document] | list[str]] (r3224178510, r3224179725). - tests: bump api_base_url assertions in embedder unit tests to /v1; drop obsolete 'raises_runtime_error_when_warm_up_fails' websearch tests; update chat-generator to_dict assertion to the fully-qualified module path produced by generate_qualified_class_name.
1 parent 0a6e420 commit 9a683c9

8 files changed

Lines changed: 45 additions & 41 deletions

File tree

integrations/perplexity/src/haystack_integrations/components/embedders/perplexity/document_embedder.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import importlib.metadata
66
from typing import Any, ClassVar
77

8-
from haystack import component, default_to_dict
8+
from haystack import component, default_from_dict, default_to_dict
99
from haystack.components.embedders import OpenAIDocumentEmbedder
1010
from haystack.utils.auth import Secret
1111

@@ -66,7 +66,7 @@ def __init__(
6666
*,
6767
api_key: Secret = Secret.from_env_var("PERPLEXITY_API_KEY"),
6868
model: str = "pplx-embed-v1-0.6b",
69-
api_base_url: str | None = "https://api.perplexity.ai",
69+
api_base_url: str | None = "https://api.perplexity.ai/v1",
7070
prefix: str = "",
7171
suffix: str = "",
7272
batch_size: int = 32,
@@ -151,3 +151,15 @@ def to_dict(self) -> dict[str, Any]:
151151
max_retries=self.max_retries,
152152
http_client_kwargs=self.http_client_kwargs,
153153
)
154+
155+
@classmethod
156+
def from_dict(cls, data: dict[str, Any]) -> "PerplexityDocumentEmbedder":
157+
"""
158+
Deserializes the component from a dictionary.
159+
160+
:param data:
161+
Dictionary to deserialize from.
162+
:returns:
163+
Deserialized component.
164+
"""
165+
return default_from_dict(cls, data)

integrations/perplexity/src/haystack_integrations/components/embedders/perplexity/text_embedder.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import importlib.metadata
66
from typing import Any, ClassVar
77

8-
from haystack import component, default_to_dict
8+
from haystack import component, default_from_dict, default_to_dict
99
from haystack.components.embedders import OpenAITextEmbedder
1010
from haystack.utils.auth import Secret
1111

@@ -61,7 +61,7 @@ def __init__(
6161
*,
6262
api_key: Secret = Secret.from_env_var("PERPLEXITY_API_KEY"),
6363
model: str = "pplx-embed-v1-0.6b",
64-
api_base_url: str | None = "https://api.perplexity.ai",
64+
api_base_url: str | None = "https://api.perplexity.ai/v1",
6565
prefix: str = "",
6666
suffix: str = "",
6767
timeout: float | None = None,
@@ -126,3 +126,15 @@ def to_dict(self) -> dict[str, Any]:
126126
max_retries=self.max_retries,
127127
http_client_kwargs=self.http_client_kwargs,
128128
)
129+
130+
@classmethod
131+
def from_dict(cls, data: dict[str, Any]) -> "PerplexityTextEmbedder":
132+
"""
133+
Deserializes the component from a dictionary.
134+
135+
:param data:
136+
Dictionary to deserialize from.
137+
:returns:
138+
Deserialized component.
139+
"""
140+
return default_from_dict(cls, data)

integrations/perplexity/src/haystack_integrations/components/generators/perplexity/chat/chat_generator.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,14 @@
77

88
from haystack import component, default_from_dict
99
from haystack.components.generators.chat import OpenAIResponsesChatGenerator
10+
from haystack.core.serialization import generate_qualified_class_name
1011
from haystack.dataclasses import StreamingCallbackT
1112
from haystack.tools import ToolsType, deserialize_tools_or_toolset_inplace
1213
from haystack.utils import deserialize_callable
1314
from haystack.utils.auth import Secret
1415

1516
_INTEGRATION_SLUG = "haystack"
1617
_PACKAGE_NAME = "perplexity-haystack"
17-
_PERPLEXITY_COMPONENT_PATH = "haystack_integrations.components.generators.perplexity.PerplexityChatGenerator"
18-
_PERPLEXITY_INTERNAL_COMPONENT_PATH = (
19-
"haystack_integrations.components.generators.perplexity.chat.chat_generator.PerplexityChatGenerator"
20-
)
2118

2219

2320
def _attribution_header() -> str:
@@ -151,7 +148,7 @@ def to_dict(self) -> dict[str, Any]:
151148
The serialized component as a dictionary.
152149
"""
153150
data = super(PerplexityChatGenerator, self).to_dict() # noqa: UP008
154-
data["type"] = _PERPLEXITY_COMPONENT_PATH
151+
data["type"] = generate_qualified_class_name(type(self))
155152
data["init_parameters"]["extra_headers"] = self.extra_headers
156153
return data
157154

@@ -175,5 +172,4 @@ def from_dict(cls, data: dict[str, Any]) -> "PerplexityChatGenerator":
175172
if serialized_callback_handler:
176173
data["init_parameters"]["streaming_callback"] = deserialize_callable(serialized_callback_handler)
177174

178-
data["type"] = _PERPLEXITY_INTERNAL_COMPONENT_PATH
179175
return default_from_dict(cls, data)

integrations/perplexity/src/haystack_integrations/components/websearch/perplexity/perplexity_websearch.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def run(
113113
self,
114114
query: str,
115115
search_params: dict[str, Any] | None = None,
116-
) -> dict[str, Any]:
116+
) -> dict[str, list[Document] | list[str]]:
117117
"""
118118
Search the web using Perplexity and return results as Documents.
119119
@@ -127,9 +127,6 @@ def run(
127127
"""
128128
if self._client is None:
129129
self.warm_up()
130-
if self._client is None:
131-
msg = "PerplexityWebSearch client failed to initialize."
132-
raise RuntimeError(msg)
133130

134131
response = self._client.post(
135132
PERPLEXITY_SEARCH_URL,
@@ -144,7 +141,7 @@ async def run_async(
144141
self,
145142
query: str,
146143
search_params: dict[str, Any] | None = None,
147-
) -> dict[str, Any]:
144+
) -> dict[str, list[Document] | list[str]]:
148145
"""
149146
Asynchronously search the web using Perplexity and return results as Documents.
150147
@@ -158,9 +155,6 @@ async def run_async(
158155
"""
159156
if self._async_client is None:
160157
self.warm_up()
161-
if self._async_client is None:
162-
msg = "PerplexityWebSearch async client failed to initialize."
163-
raise RuntimeError(msg)
164158

165159
response = await self._async_client.post(
166160
PERPLEXITY_SEARCH_URL,

integrations/perplexity/tests/test_perplexity_chat_generator.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ def test_to_dict_default_round_trip(self, monkeypatch):
104104
component = PerplexityChatGenerator()
105105
data = component.to_dict()
106106

107-
assert data["type"] == "haystack_integrations.components.generators.perplexity.PerplexityChatGenerator"
107+
assert (
108+
data["type"]
109+
== "haystack_integrations.components.generators.perplexity.chat.chat_generator.PerplexityChatGenerator"
110+
)
108111
assert data["init_parameters"]["api_key"] == Secret.from_env_var("PERPLEXITY_API_KEY").to_dict()
109112
assert data["init_parameters"] == {
110113
"api_key": Secret.from_env_var("PERPLEXITY_API_KEY").to_dict(),

integrations/perplexity/tests/test_perplexity_document_embedder.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def test_init_default(self, monkeypatch):
7070

7171
assert embedder.api_key == Secret.from_env_var(["PERPLEXITY_API_KEY"])
7272
assert embedder.model == "pplx-embed-v1-0.6b"
73-
assert embedder.api_base_url == "https://api.perplexity.ai"
73+
assert embedder.api_base_url == "https://api.perplexity.ai/v1"
7474
assert embedder.prefix == ""
7575
assert embedder.suffix == ""
7676
assert embedder.batch_size == 32
@@ -115,7 +115,7 @@ def test_to_dict(self, monkeypatch):
115115
"init_parameters": {
116116
"api_key": Secret.from_env_var("PERPLEXITY_API_KEY").to_dict(),
117117
"model": "pplx-embed-v1-0.6b",
118-
"api_base_url": "https://api.perplexity.ai",
118+
"api_base_url": "https://api.perplexity.ai/v1",
119119
"prefix": "",
120120
"suffix": "",
121121
"batch_size": 32,
@@ -176,7 +176,7 @@ def test_from_dict(self, monkeypatch):
176176
"init_parameters": {
177177
"api_key": Secret.from_env_var("PERPLEXITY_API_KEY").to_dict(),
178178
"model": "pplx-embed-v1-0.6b",
179-
"api_base_url": "https://api.perplexity.ai",
179+
"api_base_url": "https://api.perplexity.ai/v1",
180180
"prefix": "",
181181
"suffix": "",
182182
"batch_size": 32,
@@ -193,7 +193,7 @@ def test_from_dict(self, monkeypatch):
193193

194194
assert component.api_key == Secret.from_env_var(["PERPLEXITY_API_KEY"])
195195
assert component.model == "pplx-embed-v1-0.6b"
196-
assert component.api_base_url == "https://api.perplexity.ai"
196+
assert component.api_base_url == "https://api.perplexity.ai/v1"
197197
assert component.prefix == ""
198198
assert component.suffix == ""
199199
assert component.batch_size == 32

integrations/perplexity/tests/test_perplexity_text_embedder.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_init_default(self, monkeypatch):
6363
embedder = PerplexityTextEmbedder()
6464

6565
assert embedder.api_key == Secret.from_env_var(["PERPLEXITY_API_KEY"])
66-
assert embedder.api_base_url == "https://api.perplexity.ai"
66+
assert embedder.api_base_url == "https://api.perplexity.ai/v1"
6767
assert embedder.model == "pplx-embed-v1-0.6b"
6868
assert embedder.prefix == ""
6969
assert embedder.suffix == ""
@@ -77,7 +77,7 @@ def test_init_with_parameters(self):
7777
)
7878

7979
assert embedder.api_key == Secret.from_token("test-api-key")
80-
assert embedder.api_base_url == "https://api.perplexity.ai"
80+
assert embedder.api_base_url == "https://api.perplexity.ai/v1"
8181
assert embedder.model == "pplx-embed-v1-4b"
8282
assert embedder.prefix == "START"
8383
assert embedder.suffix == "END"
@@ -94,7 +94,7 @@ def test_to_dict(self, monkeypatch):
9494
"init_parameters": {
9595
"api_key": Secret.from_env_var("PERPLEXITY_API_KEY").to_dict(),
9696
"model": "pplx-embed-v1-0.6b",
97-
"api_base_url": "https://api.perplexity.ai",
97+
"api_base_url": "https://api.perplexity.ai/v1",
9898
"prefix": "",
9999
"suffix": "",
100100
"timeout": None,
@@ -139,7 +139,7 @@ def test_from_dict(self, monkeypatch):
139139
"init_parameters": {
140140
"api_key": Secret.from_env_var("PERPLEXITY_API_KEY").to_dict(),
141141
"model": "pplx-embed-v1-0.6b",
142-
"api_base_url": "https://api.perplexity.ai",
142+
"api_base_url": "https://api.perplexity.ai/v1",
143143
"prefix": "",
144144
"suffix": "",
145145
"timeout": None,
@@ -151,7 +151,7 @@ def test_from_dict(self, monkeypatch):
151151
component = PerplexityTextEmbedder.from_dict(data)
152152

153153
assert component.api_key == Secret.from_env_var(["PERPLEXITY_API_KEY"])
154-
assert component.api_base_url == "https://api.perplexity.ai"
154+
assert component.api_base_url == "https://api.perplexity.ai/v1"
155155
assert component.model == "pplx-embed-v1-0.6b"
156156
assert component.prefix == ""
157157
assert component.suffix == ""

integrations/perplexity/tests/test_perplexity_websearch.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -233,19 +233,6 @@ def test_run_empty_results(self):
233233
assert result["documents"] == []
234234
assert result["links"] == []
235235

236-
def test_run_raises_runtime_error_when_warm_up_fails_to_initialize_client(self, monkeypatch):
237-
ws = PerplexityWebSearch(api_key=Secret.from_token("test-key"))
238-
monkeypatch.setattr(ws, "warm_up", lambda: None)
239-
with pytest.raises(RuntimeError, match="PerplexityWebSearch client failed to initialize"):
240-
ws.run(query="test")
241-
242-
@pytest.mark.asyncio
243-
async def test_run_async_raises_runtime_error_when_warm_up_fails_to_initialize_client(self, monkeypatch):
244-
ws = PerplexityWebSearch(api_key=Secret.from_token("test-key"))
245-
monkeypatch.setattr(ws, "warm_up", lambda: None)
246-
with pytest.raises(RuntimeError, match="PerplexityWebSearch async client failed to initialize"):
247-
await ws.run_async(query="test")
248-
249236
def test_run_drops_none_valued_search_params(self):
250237
captured: list[httpx.Request] = []
251238
ws = PerplexityWebSearch(

0 commit comments

Comments
 (0)