- 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.
131 lines
5.9 KiB
Markdown
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
|