zotero-kb/CLAUDE.md
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

131 lines
5.9 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Zotero KB is a local FastAPI web service that reads from a Zotero SQLite database and generates structured Markdown knowledge cards for academic writing workflows. It provides project management, collection browsing, batch card generation via LLM (DeepSeek), and citation recommendation APIs.
## Development Commands
Package manager is `uv`. All commands run through `uv run`.
```bash
# Install dependencies
UV_CACHE_DIR=/tmp/uv-cache uv sync --extra dev
# Run the server
UV_CACHE_DIR=/tmp/uv-cache uv run python main.py
# Serves on http://127.0.0.1:8000
# Run all tests
UV_CACHE_DIR=/tmp/uv-cache uv run pytest -q
# Run a single test file
UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_api.py -q
# Run a single test
UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_api.py::test_create_project_endpoint -q
```
## Environment Variables
| Variable | Default | Purpose |
|----------|---------|---------|
| `ZOTERO_DATA_DIR` | `/mnt/c/Users/WSX/Zotero` | Path to Zotero data directory (must contain `zotero.sqlite`) |
| `ZOTERO_KB_WORKSPACE` | `workspace` | Workspace directory for projects, indexes, and cards |
| `ZOTERO_BRIDGE_FILE` | `workspace/bridge/selected-items.json` | Bridge file for Zotero-to-project item import |
| `DEEPSEEK_API_KEY` | — | Required when projects use `llm_provider=deepseek` |
## Architecture
### Layer Overview
`api.py` → FastAPI routes → `Workspace` / `ProjectService` / `WritingService` / `ZoteroReader` / `CardBuilder`
All business logic lives in `src/zotero_kb/`. There is no database migration system; the app creates directories on demand.
### ZoteroReader (`zotero_reader.py`)
Reads directly from `zotero.sqlite` via `sqlite3`. Key capabilities:
- `read_items(item_keys)` — full record with metadata, creators, tags, notes, attachment texts
- `get_collection_tree()` / `get_collection_items(collection_key)` — browse collections hierarchically
- `search_items(query)` — title/abstract substring search
- PDF text extraction delegates to `pdftotext` CLI; other attachments read as plain text
- Attachment paths resolve from `storage:<key>` relative to `ZOTERO_DATA_DIR/storage/`
### Workspace & Project Model (`workspace.py`, `projects.py`)
A **project** is a JSON file plus two companion files under `workspace/projects/<project_id>/`:
- `project.json` — metadata including `llm.provider`, `llm.model`, `card_language`
- `selected-items.json` — ordered list of Zotero item keys belonging to the project
- `project-index.json` — cached denormalized view rebuilt on every read
`Workspace` creates/renames/deletes projects. `ProjectService` manages item selection and rebuilds `project-index.json` by reading three shared indexes:
- `workspace/library/index/items.json` — item metadata
- `workspace/library/index/cards.json` — generated card data (supports per-language variants)
- `workspace/library/index/collections.json` — collection metadata
### Card Generation (`cards.py`, `llm.py`)
`CardBuilder.build_or_update(item, language)`:
1. Builds a **source bundle** from the item record (metadata + notes + attachment texts)
2. Hashes and caches the bundle to `library/cache/source-bundles/`
3. Calls `llm_client.generate_card(source_bundle)`
4. Renders a Markdown file to `library/collections/<collection_path>/<title> [<key>][<lang>].md`
5. Updates `items.json`, `cards.json`, and `collections.json`
The LLM layer supports two providers:
- `deepseek` — calls DeepSeek Chat API, requires `DEEPSEEK_API_KEY`
- `deterministic` (fallback) — derives card fields from abstract/notes without any API call
Cards support **language variants**: `cards.json` stores a map `item_key -> {language -> card_data}`. The `project-index.json` selects the variant matching the project's `card_language`.
### Writing Support (`writing.py`)
- `recommend_citations(project_id, prompt)` — simple term-overlap scoring across project cards
- `generate_plan(project_id, prompt)` — returns a single-section plan using the top-scored card
### Bridge Import (`bridge.py`)
The `ZOTERO_BRIDGE_FILE` (JSON with `selected_keys` array) is read by the `/api/projects/{id}/imports/selected-items` endpoint to import items that were pre-selected in Zotero. This is separate from the UI-driven `/imports/item-keys` endpoint.
### Frontend
A single `index.html` (Jinja2 template rendered as static HTML) provides the full UI. It uses vanilla JS to call the REST API. No build step or JS bundler.
## Testing
Tests use `fastapi.testclient.TestClient` with a `FakeLlmClient` injected via `create_app(config, llm_client=...)`. The fixture builder (`tests/fixtures/build_zotero_fixture.py`) creates an in-memory Zotero SQLite schema with sample data. Most tests extract route handlers directly from the FastAPI app rather than using HTTP-level client calls.
## Workspace Directory Layout
```
workspace/
bridge/
selected-items.json # bridge file from Zotero
library/
index/
items.json # item metadata index
cards.json # card data index (language variants)
collections.json # collection metadata index
collections/
<collection_path>/
<title> [<key>][<lang>].md # generated Markdown cards
cache/
source-bundles/
<key>.<lang>.json # cached source bundles
projects/
<project_id>/
project.json # project config
selected-items.json # item keys in this project
project-index.json # denormalized project view
```
## Related Subdirectories
- `zotcard/` — Zotero plugin (separate JS project, not part of the Python service)
- `zotero-rag/` — Standalone RAG search service (separate project)
- `zotero-bridge/` — Zotero plugin bridge component
- `skills/zotero-citation-planner/` — Claude skill for reading project indexes and generating citation plans