Skip to content

Commit e5be10e

Browse files
ThomasSaulouccurme
authored andcommitted
chatperplexity stream-citations in additional kwargs (#29273)
chatperplexity stream-citations in additional kwargs --------- Co-authored-by: Chester Curme <[email protected]>
1 parent 4b3848a commit e5be10e

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

libs/community/langchain_community/chat_models/perplexity.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,15 +223,21 @@ def _stream(
223223
stream_resp = self.client.chat.completions.create(
224224
messages=message_dicts, stream=True, **params
225225
)
226+
first_chunk = True
226227
for chunk in stream_resp:
227228
if not isinstance(chunk, dict):
228229
chunk = chunk.dict()
229230
if len(chunk["choices"]) == 0:
230231
continue
231232
choice = chunk["choices"][0]
233+
citations = chunk.get("citations", [])
234+
232235
chunk = self._convert_delta_to_message_chunk(
233236
choice["delta"], default_chunk_class
234237
)
238+
if first_chunk:
239+
chunk.additional_kwargs |= {"citations": citations}
240+
first_chunk = False
235241
finish_reason = choice.get("finish_reason")
236242
generation_info = (
237243
dict(finish_reason=finish_reason) if finish_reason is not None else None

libs/community/tests/unit_tests/chat_models/test_perplexity.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
"""Test Perplexity Chat API wrapper."""
22

33
import os
4+
from typing import Any, Dict, List, Optional
5+
from unittest.mock import MagicMock
46

57
import pytest
8+
from langchain_core.messages import AIMessageChunk, BaseMessageChunk
9+
from pytest_mock import MockerFixture
610

711
from langchain_community.chat_models import ChatPerplexity
812

@@ -40,3 +44,58 @@ def test_perplexity_initialization() -> None:
4044
]:
4145
assert model.request_timeout == 1
4246
assert model.pplx_api_key == "test"
47+
48+
49+
@pytest.mark.requires("openai")
50+
def test_perplexity_stream_includes_citations(mocker: MockerFixture) -> None:
51+
"""Test that the stream method includes citations in the additional_kwargs."""
52+
llm = ChatPerplexity(
53+
model="test",
54+
timeout=30,
55+
verbose=True,
56+
)
57+
mock_chunk_0 = {
58+
"choices": [
59+
{
60+
"delta": {
61+
"content": "Hello ",
62+
},
63+
"finish_reason": None,
64+
}
65+
],
66+
"citations": ["example.com", "example2.com"],
67+
}
68+
mock_chunk_1 = {
69+
"choices": [
70+
{
71+
"delta": {
72+
"content": "Perplexity",
73+
},
74+
"finish_reason": None,
75+
}
76+
],
77+
"citations": ["example.com", "example2.com"],
78+
}
79+
mock_chunks: List[Dict[str, Any]] = [mock_chunk_0, mock_chunk_1]
80+
mock_stream = MagicMock()
81+
mock_stream.__iter__.return_value = mock_chunks
82+
patcher = mocker.patch.object(
83+
llm.client.chat.completions, "create", return_value=mock_stream
84+
)
85+
stream = llm.stream("Hello langchain")
86+
full: Optional[BaseMessageChunk] = None
87+
for i, chunk in enumerate(stream):
88+
full = chunk if full is None else full + chunk
89+
assert chunk.content == mock_chunks[i]["choices"][0]["delta"]["content"]
90+
if i == 0:
91+
assert chunk.additional_kwargs["citations"] == [
92+
"example.com",
93+
"example2.com",
94+
]
95+
else:
96+
assert "citations" not in chunk.additional_kwargs
97+
assert isinstance(full, AIMessageChunk)
98+
assert full.content == "Hello Perplexity"
99+
assert full.additional_kwargs == {"citations": ["example.com", "example2.com"]}
100+
101+
patcher.assert_called_once()

0 commit comments

Comments
 (0)