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

81 lines
3.2 KiB
Python

from pathlib import Path
from zotero_kb.cards import CardBuilder
from zotero_kb.config import AppConfig
from zotero_kb.projects import ProjectService
from zotero_kb.workspace import Workspace
from zotero_kb.writing import WritingService
from zotero_kb.zotero_reader import ZoteroItemRecord
class FakeLlmClient:
def generate_card(self, source_bundle: dict[str, object]) -> dict[str, object]:
title = str(source_bundle["title"])
if "Scoped" in title:
summary = "Project-scoped retrieval improves drafting support."
claims = ["Project scoping improves citation precision."]
hints = ["Use for scoped retrieval arguments."]
else:
summary = "Broad retrieval baseline for comparison."
claims = ["Baseline retrieval may drift."]
hints = ["Use as a contrast only."]
return {
"summary": summary,
"core_claims": claims,
"methods": ["Method details."],
"evidence": ["Evidence details."],
"quotable_passages": claims,
"writing_hints": hints,
"keywords": ["retrieval", "writing"],
}
def _build_item(item_key: str, title: str) -> ZoteroItemRecord:
return ZoteroItemRecord(
item_key=item_key,
title=title,
creators=["Alice Smith"],
year="2024",
item_type="journalArticle",
abstract=title,
tags=["retrieval"],
collection_paths=[["Theory", "Drafting"]],
notes=[title],
attachments=[],
attachment_texts=[title],
)
def test_recommend_citations_only_reads_project_items(tmp_path: Path) -> None:
config = AppConfig(workspace_dir=tmp_path / "workspace", zotero_data_dir=tmp_path / "zotero")
workspace = Workspace(config)
workspace.create_project("thesis-ch2", "Thesis Chapter 2", "openai", "gpt-5-mini", "en")
builder = CardBuilder(config.workspace_dir, FakeLlmClient())
builder.build_or_update(_build_item("PAPER0001", "Scoped Retrieval for Drafting"))
builder.build_or_update(_build_item("PAPER0002", "Broad Retrieval Baseline"))
project_service = ProjectService(config.workspace_dir)
project_service.add_items("thesis-ch2", ["PAPER0001"])
service = WritingService(config.workspace_dir)
result = service.recommend_citations("thesis-ch2", "support scoped retrieval during drafting")
assert [item["item_key"] for item in result["results"]] == ["PAPER0001"]
def test_generate_plan_returns_structured_sections(tmp_path: Path) -> None:
config = AppConfig(workspace_dir=tmp_path / "workspace", zotero_data_dir=tmp_path / "zotero")
workspace = Workspace(config)
workspace.create_project("thesis-ch2", "Thesis Chapter 2", "openai", "gpt-5-mini", "en")
builder = CardBuilder(config.workspace_dir, FakeLlmClient())
builder.build_or_update(_build_item("PAPER0001", "Scoped Retrieval for Drafting"))
project_service = ProjectService(config.workspace_dir)
project_service.add_items("thesis-ch2", ["PAPER0001"])
service = WritingService(config.workspace_dir)
plan = service.generate_plan("thesis-ch2", "argue that project scoping improves drafting")
assert "sections" in plan
assert plan["sections"][0]["citations"][0]["item_key"] == "PAPER0001"