mirror of
https://github.com/hwchase17/langchain.git
synced 2025-07-05 04:38:26 +00:00
community: fix perplexity response parameters not being included in model response (#30440)
This pull request includes enhancements to the `perplexity.py` file in the `chat_models` module, focusing on improving the handling of additional keyword arguments (`additional_kwargs`) in message processing methods. Additionally, new unit tests have been added to ensure the correct inclusion of citations, images, and related questions in the `additional_kwargs`. Issue: resolves https://github.com/langchain-ai/langchain/issues/30439 Enhancements to `perplexity.py`: * [`libs/community/langchain_community/chat_models/perplexity.py`](diffhunk://#diff-d3e4d7b277608683913b53dcfdbd006f0f4a94d110d8b9ac7acf855f1f22207fL208-L212): Modified the `_convert_delta_to_message_chunk`, `_stream`, and `_generate` methods to handle `additional_kwargs`, which include citations, images, and related questions. [[1]](diffhunk://#diff-d3e4d7b277608683913b53dcfdbd006f0f4a94d110d8b9ac7acf855f1f22207fL208-L212) [[2]](diffhunk://#diff-d3e4d7b277608683913b53dcfdbd006f0f4a94d110d8b9ac7acf855f1f22207fL277-L286) [[3]](diffhunk://#diff-d3e4d7b277608683913b53dcfdbd006f0f4a94d110d8b9ac7acf855f1f22207fR324-R331) New unit tests: * [`libs/community/tests/unit_tests/chat_models/test_perplexity.py`](diffhunk://#diff-dab956d79bd7d17a0f5dea3f38ceab0d583b43b63eb1b29138ee9b6b271ba1d9R119-R275): Added new tests `test_perplexity_stream_includes_citations_and_images` and `test_perplexity_stream_includes_citations_and_related_questions` to verify that the `stream` method correctly includes citations, images, and related questions in the `additional_kwargs`.
This commit is contained in:
parent
7664874a0d
commit
75823d580b
@ -345,16 +345,25 @@ class ChatPerplexity(BaseChatModel):
|
||||
if len(chunk["choices"]) == 0:
|
||||
continue
|
||||
choice = chunk["choices"][0]
|
||||
citations = chunk.get("citations", [])
|
||||
|
||||
additional_kwargs = {}
|
||||
if first_chunk:
|
||||
additional_kwargs["citations"] = chunk.get("citations", [])
|
||||
for attr in ["images", "related_questions"]:
|
||||
if attr in chunk:
|
||||
additional_kwargs[attr] = chunk[attr]
|
||||
|
||||
chunk = self._convert_delta_to_message_chunk(
|
||||
choice["delta"], default_chunk_class
|
||||
)
|
||||
|
||||
if isinstance(chunk, AIMessageChunk) and usage_metadata:
|
||||
chunk.usage_metadata = usage_metadata
|
||||
|
||||
if first_chunk:
|
||||
chunk.additional_kwargs |= {"citations": citations}
|
||||
chunk.additional_kwargs |= additional_kwargs
|
||||
first_chunk = False
|
||||
|
||||
finish_reason = choice.get("finish_reason")
|
||||
generation_info = (
|
||||
dict(finish_reason=finish_reason) if finish_reason is not None else None
|
||||
@ -386,9 +395,14 @@ class ChatPerplexity(BaseChatModel):
|
||||
else:
|
||||
usage_metadata = None
|
||||
|
||||
additional_kwargs = {"citations": response.citations}
|
||||
for attr in ["images", "related_questions"]:
|
||||
if hasattr(response, attr):
|
||||
additional_kwargs[attr] = getattr(response, attr)
|
||||
|
||||
message = AIMessage(
|
||||
content=response.choices[0].message.content,
|
||||
additional_kwargs={"citations": response.citations},
|
||||
additional_kwargs=additional_kwargs,
|
||||
usage_metadata=usage_metadata,
|
||||
)
|
||||
return ChatResult(generations=[ChatGeneration(message=message)])
|
||||
|
@ -116,3 +116,160 @@ def test_perplexity_stream_includes_citations(mocker: MockerFixture) -> None:
|
||||
assert full.additional_kwargs == {"citations": ["example.com", "example2.com"]}
|
||||
|
||||
patcher.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.requires("openai")
|
||||
def test_perplexity_stream_includes_citations_and_images(mocker: MockerFixture) -> None:
|
||||
"""Test that the stream method includes citations in the additional_kwargs."""
|
||||
llm = ChatPerplexity(
|
||||
model="test",
|
||||
timeout=30,
|
||||
verbose=True,
|
||||
)
|
||||
mock_chunk_0 = {
|
||||
"choices": [
|
||||
{
|
||||
"delta": {
|
||||
"content": "Hello ",
|
||||
},
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
"citations": ["example.com", "example2.com"],
|
||||
"images": [
|
||||
{
|
||||
"image_url": "mock_image_url",
|
||||
"origin_url": "mock_origin_url",
|
||||
"height": 100,
|
||||
"width": 100,
|
||||
}
|
||||
],
|
||||
}
|
||||
mock_chunk_1 = {
|
||||
"choices": [
|
||||
{
|
||||
"delta": {
|
||||
"content": "Perplexity",
|
||||
},
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
"citations": ["example.com", "example2.com"],
|
||||
"images": [
|
||||
{
|
||||
"image_url": "mock_image_url",
|
||||
"origin_url": "mock_origin_url",
|
||||
"height": 100,
|
||||
"width": 100,
|
||||
}
|
||||
],
|
||||
}
|
||||
mock_chunks: List[Dict[str, Any]] = [mock_chunk_0, mock_chunk_1]
|
||||
mock_stream = MagicMock()
|
||||
mock_stream.__iter__.return_value = mock_chunks
|
||||
patcher = mocker.patch.object(
|
||||
llm.client.chat.completions, "create", return_value=mock_stream
|
||||
)
|
||||
stream = llm.stream("Hello langchain")
|
||||
full: Optional[BaseMessageChunk] = None
|
||||
for i, chunk in enumerate(stream):
|
||||
full = chunk if full is None else full + chunk
|
||||
assert chunk.content == mock_chunks[i]["choices"][0]["delta"]["content"]
|
||||
if i == 0:
|
||||
assert chunk.additional_kwargs["citations"] == [
|
||||
"example.com",
|
||||
"example2.com",
|
||||
]
|
||||
assert chunk.additional_kwargs["images"] == [
|
||||
{
|
||||
"image_url": "mock_image_url",
|
||||
"origin_url": "mock_origin_url",
|
||||
"height": 100,
|
||||
"width": 100,
|
||||
}
|
||||
]
|
||||
else:
|
||||
assert "citations" not in chunk.additional_kwargs
|
||||
assert "images" not in chunk.additional_kwargs
|
||||
assert isinstance(full, AIMessageChunk)
|
||||
assert full.content == "Hello Perplexity"
|
||||
assert full.additional_kwargs == {
|
||||
"citations": ["example.com", "example2.com"],
|
||||
"images": [
|
||||
{
|
||||
"image_url": "mock_image_url",
|
||||
"origin_url": "mock_origin_url",
|
||||
"height": 100,
|
||||
"width": 100,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
patcher.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.requires("openai")
|
||||
def test_perplexity_stream_includes_citations_and_related_questions(
|
||||
mocker: MockerFixture,
|
||||
) -> None:
|
||||
"""Test that the stream method includes citations in the additional_kwargs."""
|
||||
llm = ChatPerplexity(
|
||||
model="test",
|
||||
timeout=30,
|
||||
verbose=True,
|
||||
)
|
||||
mock_chunk_0 = {
|
||||
"choices": [
|
||||
{
|
||||
"delta": {
|
||||
"content": "Hello ",
|
||||
},
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
"citations": ["example.com", "example2.com"],
|
||||
"related_questions": ["example_question_1", "example_question_2"],
|
||||
}
|
||||
mock_chunk_1 = {
|
||||
"choices": [
|
||||
{
|
||||
"delta": {
|
||||
"content": "Perplexity",
|
||||
},
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
"citations": ["example.com", "example2.com"],
|
||||
"related_questions": ["example_question_1", "example_question_2"],
|
||||
}
|
||||
mock_chunks: List[Dict[str, Any]] = [mock_chunk_0, mock_chunk_1]
|
||||
mock_stream = MagicMock()
|
||||
mock_stream.__iter__.return_value = mock_chunks
|
||||
patcher = mocker.patch.object(
|
||||
llm.client.chat.completions, "create", return_value=mock_stream
|
||||
)
|
||||
stream = llm.stream("Hello langchain")
|
||||
full: Optional[BaseMessageChunk] = None
|
||||
for i, chunk in enumerate(stream):
|
||||
full = chunk if full is None else full + chunk
|
||||
assert chunk.content == mock_chunks[i]["choices"][0]["delta"]["content"]
|
||||
if i == 0:
|
||||
assert chunk.additional_kwargs["citations"] == [
|
||||
"example.com",
|
||||
"example2.com",
|
||||
]
|
||||
assert chunk.additional_kwargs["related_questions"] == [
|
||||
"example_question_1",
|
||||
"example_question_2",
|
||||
]
|
||||
else:
|
||||
assert "citations" not in chunk.additional_kwargs
|
||||
assert "related_questions" not in chunk.additional_kwargs
|
||||
assert isinstance(full, AIMessageChunk)
|
||||
assert full.content == "Hello Perplexity"
|
||||
assert full.additional_kwargs == {
|
||||
"citations": ["example.com", "example2.com"],
|
||||
"related_questions": ["example_question_1", "example_question_2"],
|
||||
}
|
||||
|
||||
patcher.assert_called_once()
|
||||
|
@ -1,4 +1,5 @@
|
||||
version = 1
|
||||
revision = 1
|
||||
requires-python = ">=3.9, <4.0"
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.12.4' and platform_python_implementation == 'PyPy'",
|
||||
@ -1531,6 +1532,7 @@ requires-dist = [
|
||||
{ name = "requests", specifier = ">=2,<3" },
|
||||
{ name = "sqlalchemy", specifier = ">=1.4,<3" },
|
||||
]
|
||||
provides-extras = ["community", "anthropic", "openai", "azure-ai", "cohere", "google-vertexai", "google-genai", "fireworks", "ollama", "together", "mistralai", "huggingface", "groq", "aws", "deepseek", "xai"]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
codespell = [{ name = "codespell", specifier = ">=2.2.0,<3.0.0" }]
|
||||
@ -1745,7 +1747,7 @@ typing = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.3.45"
|
||||
version = "0.3.47"
|
||||
source = { editable = "../core" }
|
||||
dependencies = [
|
||||
{ name = "jsonpatch" },
|
||||
@ -1803,7 +1805,7 @@ typing = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-tests"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = { editable = "../standard-tests" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
|
Loading…
Reference in New Issue
Block a user