feat: brain detail sheet — screenshot for links, editable notes, spelling fix
- Link detail: shows screenshot image (clickable to open URL), URL, summary, tags - Note detail: click note text to edit, save/cancel buttons - Notes: AI now fixes spelling/grammar instead of rewriting - AI returns corrected_text field for notes, worker replaces raw_content - Removed verbose meta grid (folder/confidence/status/saved) - Folder shown as a pill badge in meta line Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -401,12 +401,25 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if selectedItem.url}
|
||||
<a class="detail-url" href={selectedItem.url} target="_blank" rel="noopener">{selectedItem.url}</a>
|
||||
<!-- Link: show screenshot + URL + tags -->
|
||||
{#if selectedItem.type === 'link'}
|
||||
{#if selectedItem.assets?.some(a => a.asset_type === 'screenshot')}
|
||||
<a class="detail-screenshot" href={selectedItem.url} target="_blank" rel="noopener">
|
||||
<img src="/api/brain/storage/{selectedItem.id}/screenshot/screenshot.png" alt="" />
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
{#if selectedItem.url}
|
||||
<a class="detail-url" href={selectedItem.url} target="_blank" rel="noopener">{selectedItem.url}</a>
|
||||
{/if}
|
||||
|
||||
{#if selectedItem.summary}
|
||||
<div class="detail-summary">{selectedItem.summary}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<!-- Note: editable content -->
|
||||
{#if selectedItem.type === 'note'}
|
||||
<!-- Editable note content -->
|
||||
<div class="detail-content">
|
||||
{#if editingNote}
|
||||
<textarea
|
||||
@@ -426,10 +439,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if selectedItem.summary}
|
||||
<div class="detail-summary">{selectedItem.summary}</div>
|
||||
{/if}
|
||||
|
||||
{#if selectedItem.tags && selectedItem.tags.length > 0}
|
||||
<div class="detail-tags">
|
||||
{#each selectedItem.tags as tag}
|
||||
@@ -439,7 +448,7 @@
|
||||
{/if}
|
||||
|
||||
<div class="detail-meta-line">
|
||||
{#if selectedItem.folder}<span>{selectedItem.folder}</span>{/if}
|
||||
{#if selectedItem.folder}<span class="meta-folder-pill">{selectedItem.folder}</span>{/if}
|
||||
<span>{formatDate(selectedItem.created_at)}</span>
|
||||
</div>
|
||||
|
||||
@@ -755,13 +764,27 @@
|
||||
.close-btn:hover { background: rgba(35,26,17,0.08); color: #1e1812; }
|
||||
.close-btn svg { width: 20px; height: 20px; }
|
||||
|
||||
.detail-screenshot {
|
||||
display: block; border-radius: 14px; overflow: hidden;
|
||||
margin-bottom: 16px; border: 1px solid rgba(35,26,17,0.08);
|
||||
}
|
||||
.detail-screenshot img {
|
||||
width: 100%; height: auto; display: block; max-height: 300px; object-fit: cover;
|
||||
}
|
||||
.detail-screenshot:hover { opacity: 0.95; }
|
||||
|
||||
.detail-url {
|
||||
display: block; font-size: 0.88rem; color: #8c7b69;
|
||||
margin-bottom: 16px; word-break: break-all;
|
||||
display: block; font-size: 0.85rem; color: #8c7b69;
|
||||
margin-bottom: 14px; word-break: break-all;
|
||||
text-decoration: none;
|
||||
}
|
||||
.detail-url:hover { color: #1e1812; text-decoration: underline; }
|
||||
|
||||
.meta-folder-pill {
|
||||
background: rgba(35,26,17,0.06); padding: 2px 10px;
|
||||
border-radius: 999px; font-weight: 600;
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -15,13 +15,16 @@ Given an item (URL, note, document, or file), you must return structured JSON wi
|
||||
- folder: exactly 1 from this list: {json.dumps(FOLDERS)}
|
||||
- tags: exactly 2 or 3 from this list: {json.dumps(TAGS)}
|
||||
- title: a concise, normalized title (max 80 chars)
|
||||
- summary: a 1-2 sentence summary of the content
|
||||
- summary: a 1-2 sentence summary of the content (for links/documents only)
|
||||
- corrected_text: for NOTES ONLY — return the original note text with spelling/grammar fixed. Keep the original meaning, tone, and structure. Only fix typos and obvious errors. Return empty string for non-notes.
|
||||
- confidence: a float 0.0-1.0 indicating how confident you are
|
||||
|
||||
Rules:
|
||||
- NEVER invent folders or tags not in the lists above
|
||||
- NEVER skip classification
|
||||
- NEVER return freeform text outside the schema
|
||||
- For notes: do NOT summarize. Keep the original text. Only fix spelling.
|
||||
- For notes: the summary field should be a very short 5-10 word description, not a rewrite.
|
||||
- Always return valid JSON matching the schema exactly"""
|
||||
|
||||
RESPONSE_SCHEMA = {
|
||||
@@ -41,9 +44,10 @@ RESPONSE_SCHEMA = {
|
||||
},
|
||||
"title": {"type": "string"},
|
||||
"summary": {"type": "string"},
|
||||
"corrected_text": {"type": "string"},
|
||||
"confidence": {"type": "number"},
|
||||
},
|
||||
"required": ["folder", "tags", "title", "summary", "confidence"],
|
||||
"required": ["folder", "tags", "title", "summary", "corrected_text", "confidence"],
|
||||
"additionalProperties": False,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -111,6 +111,11 @@ async def _process_item(item_id: str):
|
||||
item.title = classification.get("title") or title or "Untitled"
|
||||
item.folder = classification.get("folder", "Knowledge")
|
||||
item.tags = classification.get("tags", ["reference", "read-later"])
|
||||
|
||||
# For notes: replace raw_content with spell-corrected version
|
||||
corrected = classification.get("corrected_text", "")
|
||||
if item.type == "note" and corrected and corrected.strip():
|
||||
item.raw_content = corrected
|
||||
item.summary = classification.get("summary")
|
||||
item.confidence = classification.get("confidence", 0.0)
|
||||
item.extracted_text = extracted_text
|
||||
|
||||
Reference in New Issue
Block a user