zotero-kb/tests/test_llm.py
Saberlve aaafa78883 feat: Add multilingual support for project cards and attachments
- Introduced `card_language` attribute in ProjectRecord and Workspace classes to handle multiple languages for project cards.
- Updated project creation and renaming methods to accept and store the card language.
- Enhanced ZoteroReader to read and return attachment metadata, including language-specific summaries and claims.
- Modified LLM client to generate card content based on the specified language, supporting both English and Chinese.
- Updated tests to cover new functionality, ensuring correct handling of multilingual card generation and retrieval.
- Adjusted UI tests to verify the presence of language selection options and proper rendering of multilingual content.
2026-04-22 10:21:03 +08:00

93 lines
3.7 KiB
Python

import json
import pytest
from zotero_kb.llm import DeepSeekCardGenerationClient, create_card_generation_client
def test_create_card_generation_client_requires_deepseek_api_key() -> None:
with pytest.raises(ValueError, match="DEEPSEEK_API_KEY"):
create_card_generation_client("deepseek", "deepseek-chat", env={})
def test_deepseek_client_uses_env_api_key_and_parses_json() -> None:
captured = {}
def fake_request(url: str, payload: dict[str, object], headers: dict[str, str]) -> dict[str, object]:
captured["url"] = url
captured["payload"] = payload
captured["headers"] = headers
return {
"choices": [
{
"message": {
"content": json.dumps(
{
"summary": "DeepSeek summary",
"core_claims": ["Claim A"],
"methods": ["Method A"],
"evidence": ["Evidence A"],
"citations": [
{
"claim": "Claim A",
"quote": "Exact supporting quote.",
"paraphrase": "Paraphrased support.",
"quote_source": "attachment_texts",
"use_case": "direct_quote",
}
],
"quotable_passages": ["Quote A"],
"writing_hints": ["Hint A"],
"keywords": ["kw-a"],
}
)
}
}
]
}
client = create_card_generation_client(
"deepseek",
"deepseek-chat",
env={"DEEPSEEK_API_KEY": "sk-test"},
request_fn=fake_request,
)
result = client.generate_card(
{
"title": "Scoped Retrieval for Drafting",
"abstract": "Merged metadata improves drafting.",
"card_language": "zh",
"notes": ["Project scoping helps."],
"attachment_texts": ["Attachment evidence."],
"tags": ["retrieval"],
}
)
assert result["summary"] == "DeepSeek summary"
assert "locator" not in result["citations"][0]
assert captured["url"] == "https://api.deepseek.com/v1/chat/completions"
assert captured["payload"]["model"] == "deepseek-chat"
assert "Return 1-3 citations whenever the source bundle contains usable supporting text" in captured["payload"]["messages"][1]["content"]
assert "quote_source must identify where the quote came from" in captured["payload"]["messages"][1]["content"]
assert "Write summary, core_claims, methods, evidence, paraphrase fields, and writing_hints in Chinese." in captured["payload"]["messages"][1]["content"]
assert captured["headers"]["Authorization"] == "Bearer sk-test"
def test_deepseek_client_strips_markdown_fences() -> None:
client = DeepSeekCardGenerationClient(
api_key="sk-test",
request_fn=lambda *_args, **_kwargs: {
"choices": [
{
"message": {
"content": "```json\n{\"summary\":\"Fence summary\",\"core_claims\":[],\"methods\":[],\"evidence\":[],\"citations\":[],\"quotable_passages\":[],\"writing_hints\":[],\"keywords\":[]}\n```"
}
}
]
},
)
result = client.generate_card({"title": "Paper"})
assert result["summary"] == "Fence summary"