zotero-kb/tests/test_cards.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

99 lines
4.1 KiB
Python

import json
from pathlib import Path
from zotero_kb.cards import CardBuilder
from zotero_kb.zotero_reader import ZoteroItemRecord
class FakeLlmClient:
def generate_card(self, source_bundle: dict[str, object]) -> dict[str, object]:
language = str(source_bundle.get("card_language", "en"))
return {
"summary": "中文卡片摘要。" if language == "zh" else "Merged metadata and attachment text improve drafting support.",
"core_claims": [
"中文卡片 claim。" if language == "zh" else "Project-scoped cards reduce irrelevant retrieval.",
],
"methods": [
"Combines notes, metadata, and full text.",
],
"evidence": [
"The merged pipeline improved citation precision.",
],
"citations": [
{
"claim": "Project-scoped cards reduce irrelevant retrieval.",
"quote": "Project-scoped card retrieval improves citation precision during drafting.",
"paraphrase": "Scoped retrieval improved citation precision during drafting.",
"quote_source": "attachment_texts",
"use_case": "direct_quote",
}
],
"quotable_passages": [
"Project-scoped card retrieval improves citation precision during drafting.",
],
"writing_hints": [
"Use when arguing for scoped retrieval during drafting.",
],
"keywords": ["retrieval", "writing"],
}
def test_build_card_writes_markdown_and_indexes(tmp_path: Path) -> None:
item = ZoteroItemRecord(
item_key="PAPER0001",
title="Card Pipelines for Research Writing",
creators=["Alice Smith", "Bob Li"],
year="2024",
item_type="journalArticle",
abstract="Merged metadata and notes improve drafting support.",
tags=["llm", "writing"],
collection_paths=[["Theory", "Drafting"]],
notes=["Merged notes matter."],
attachments=[
{
"path": str(tmp_path / "zotero" / "storage" / "ATTACH01" / "paper.txt"),
"filename": "paper.txt",
"content_type": "text/plain",
"is_pdf": False,
}
],
attachment_texts=["This paper studies card pipelines for research writing."],
)
builder = CardBuilder(workspace_dir=tmp_path, llm_client=FakeLlmClient())
result = builder.build_or_update(item, "en")
expected_path = (
tmp_path
/ "library"
/ "collections"
/ "Theory"
/ "Drafting"
/ "Card Pipelines for Research Writing [PAPER0001][en].md"
)
assert result.card_path == expected_path
card_text = result.card_path.read_text(encoding="utf-8")
assert card_text.startswith("---")
assert "# Citations" in card_text
assert "quote_source: attachment_texts" in card_text
assert "locator:" not in card_text
cards_index = json.loads((tmp_path / "library" / "index" / "cards.json").read_text(encoding="utf-8"))
assert cards_index["PAPER0001"]["en"]["title"] == "Card Pipelines for Research Writing"
assert cards_index["PAPER0001"]["en"]["language"] == "en"
assert cards_index["PAPER0001"]["en"]["citations"][0]["use_case"] == "direct_quote"
assert "locator" not in cards_index["PAPER0001"]["en"]["citations"][0]
assert cards_index["PAPER0001"]["en"]["attachments"][0]["filename"] == "paper.txt"
assert cards_index["PAPER0001"]["en"]["attachments"][0]["is_pdf"] is False
items_index = json.loads((tmp_path / "library" / "index" / "items.json").read_text(encoding="utf-8"))
assert items_index["PAPER0001"]["card_path"] == str(expected_path)
assert items_index["PAPER0001"]["card_paths"]["en"] == str(expected_path)
source_bundle = json.loads(
(tmp_path / "library" / "cache" / "source-bundles" / "PAPER0001.en.json").read_text(encoding="utf-8")
)
assert source_bundle["item_key"] == "PAPER0001"
assert source_bundle["card_language"] == "en"
assert source_bundle["attachments"][0]["filename"] == "paper.txt"