6.6 KiB
6.6 KiB
Import + Card Generation Two-Step Design
Status
Draft — not yet approved.
Overview
Split the current "import文献 + immediately generate cards" flow into two distinct steps:
- Import — items are registered to a project, but cards are NOT generated yet. The system checks a global registry for existing cards.
- Manual batch generate — user manually selects pending items and triggers card generation. Same item across different projects reuses existing cards (hash-based deduplication).
Data Model
Global Registry (existing, unchanged)
library/index/items.json— global item metadata registry, keyed byitem_keylibrary/index/cards.json— global card index, keyed byitem_key
Project Registry (existing, extended)
projects/{project_id}/selected-items.json— list ofitem_keys associated with the projectprojects/{project_id}/pending-items.json— removed — pending status is computed dynamically asselected_itemsminus keys present incards.json. No separate tracking file needed.
Import State
For each item in a project, one of two states:
| State | Meaning |
|---|---|
pending |
item is imported but no card exists in cards.json |
done |
card exists in cards.json for this item_key |
API Endpoints
GET /api/projects/{project_id}/import-state
Returns the import state of all items in a project.
Response:
{
"project_id": "proj-123",
"items": [
{
"item_key": "ABCD1234",
"title": "Paper Title",
"creators": ["Author A", "Author B"],
"year": 2024,
"item_type": "journalArticle",
"card_status": "done"
},
{
"item_key": "EFGH5678",
"title": "Another Paper",
"creators": ["Author C"],
"year": 2023,
"item_type": "conferencePaper",
"card_status": "pending"
}
],
"pending_count": 1,
"done_count": 1
}
Logic: Iterate selected-items.json, for each item_key check if it exists in cards.json. If yes → done, else → pending.
POST /api/projects/{project_id}/cards/generate
Receives a list of item_keys to generate cards for. Generates cards one by one, updates cards.json.
Request:
{
"item_keys": ["EFGH5678", "IJKL9012"]
}
Response (streaming or incremental):
{
"project_id": "proj-123",
"generated": ["EFGH5678"],
"failed": [],
"items": [
{ "item_key": "EFGH5678", "title": "...", "creators": [...], "card_status": "done" }
]
}
Logic:
- For each
item_keyinitem_keys:- Read item metadata from
items.json(or from Zotero reader if not yet in items.json) - Call
CardBuilder.build_or_update()which computessource_hashand either creates or updates the card - Send incremental progress event (SSE or via callback)
- Read item metadata from
- After all complete, return the updated item states.
POST /api/projects/{project_id}/imports/item-keys (existing, extended)
When items are imported, they are added to selected-items.json. Cards are NOT generated immediately.
Frontend: Import Window Layout
Two-Column Layout
┌─────────────────────────────────────────────────────────┐
│ [title bar: 导入文献] [_] [□] [×] │
├───────────────────────┬─────────────────────────────────┤
│ LEFT (40%) │ RIGHT (60%) │
│ ┌─────────────────┐ │ ┌───────────────────────────┐ │
│ │ Search... │ │ │ Title: ... │ │
│ └─────────────────┘ │ │ Authors: ... │ │
│ ┌─────────────────┐ │ │ Year: ... │ │
│ │ □ Paper A [✓] │ │ │ Type: journalArticle │ │
│ │ ☑ Paper B │ │ │ Abstract: ... │ │
│ │ ✓ Paper C │ │ │ Tags: tag1, tag2 │ │
│ │ □ Paper D │ │ └───────────────────────────┘ │
│ └─────────────────┘ │ │
│ Pending (2) Done (1) │ │
├───────────────────────┴─────────────────────────────────┤
│ [生成选中卡片 (2)] │
└─────────────────────────────────────────────────────────┘
Visual States
- pending items — light background, checkbox visible, unchecked by default
- done items — green tint / checkmark, no checkbox, not selectable for generation
- selected pending — highlighted border, checkbox checked
- generating — spinner icon, row slightly dimmed
Interactions
- Click item in left list → right panel shows metadata preview
- Click checkbox on pending item → toggles selection
- "Select All Pending" link at top of list
- Click "生成选中卡片 (N)" button → triggers
POST .../cards/generate - During generation: button becomes progress bar "生成 X/Y",completed items turn done in real time
Card Status Legend
Shown at bottom of left panel:
Pending (N) ● Done (N) ✓
Deduplication Logic
CardBuilder.build_or_update() computes source_hash from:
{
item_key, title, creators, year, item_type,
abstract, tags, collection_paths, notes, attachment_texts
}
- If
cards.jsonalready has an entry for thisitem_keywith the samesource_hash→ skip LLM call, card already up to date - If hash differs → regenerate (overwrite)
- This means the same
item_keyimported into multiple projects will reuse the same card if the source hasn't changed
Error Handling
- If a single item fails to generate (LLM error, missing data), mark it as failed and continue with others
- Failed items shown with error icon, can be retried individually or as batch
- Return
failedarray in response with error reasons
Out of Scope
- Streaming/SSE for real-time progress (use simple polling or single request for now)
- Background job queue
- Version history for regenerated cards