feat(facts): pictures as part of a statement, kept next to the raw source #13

Merged
k.renner merged 1 commits from feat/fact-images into main 2026-09-25 07:55:43 +00:00
Member

"This is the type label of our dishwasher" plus a photo → one raw source with the label transcribed and the photo beside it.

  • Model: Attachment(MediaType, Bytes, Caption); FactStatement and RawSource carry attachments. RawSource.Validate rejects unsupported media types (jpeg/png/webp/gif allowed), empty and >8 MiB.
  • Port INoteStore: CreateAsync(path, byte[]) for binaries and BrowseUrl(path) for a human link into the store. Gitea implements both; contract test added.
  • Drafter: images go to the Messages API as base64 image blocks ahead of the text; the prompt asks for exact transcription of every identifier printed and [unreadable] where it cannot read, never a guess.
  • Deposit: pictures land as raw/<note-stem>-<n>.<ext> (so they follow the note's suffix), listed in attachments: frontmatter and embedded with ![caption](file) at the end of the body. Obsidian and the distill agent see them next to the note.
  • Page: "Add picture" (file picker, camera on phones) or paste (facts.js moves clipboard images onto the hidden InputFile, so they stream like picked files). Browser-side resize to 1600px JPEG. Thumbnails with remove. The raw page lists attachments with links to the Gitea file.
  • Machine API unchanged.

Suite: 140 green (contract for binary create on the Gitea fake, image-block test on the Anthropic fake, deposit + record tests with a picture).

🤖 Generated with Claude Code

"This is the type label of our dishwasher" plus a photo → one raw source with the label transcribed and the photo beside it. - **Model**: `Attachment(MediaType, Bytes, Caption)`; `FactStatement` and `RawSource` carry attachments. `RawSource.Validate` rejects unsupported media types (jpeg/png/webp/gif allowed), empty and >8 MiB. - **Port** `INoteStore`: `CreateAsync(path, byte[])` for binaries and `BrowseUrl(path)` for a human link into the store. Gitea implements both; contract test added. - **Drafter**: images go to the Messages API as base64 image blocks ahead of the text; the prompt asks for exact transcription of every identifier printed and `[unreadable]` where it cannot read, never a guess. - **Deposit**: pictures land as `raw/<note-stem>-<n>.<ext>` (so they follow the note's suffix), listed in `attachments:` frontmatter and embedded with `![caption](file)` at the end of the body. Obsidian and the distill agent see them next to the note. - **Page**: "Add picture" (file picker, camera on phones) or paste (`facts.js` moves clipboard images onto the hidden `InputFile`, so they stream like picked files). Browser-side resize to 1600px JPEG. Thumbnails with remove. The raw page lists attachments with links to the Gitea file. - Machine API unchanged. Suite: 140 green (contract for binary create on the Gitea fake, image-block test on the Anthropic fake, deposit + record tests with a picture). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-bot added 1 commit 2026-09-25 07:52:17 +00:00
feat(facts): pictures as part of a statement, kept next to the raw source
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
c94afb004c
A statement may carry images (a type label, for instance). The drafter
sees them as image blocks and transcribes what is printed; the deposit
stores each picture beside the note as raw/<stem>-<n>.<ext>, lists it in
the frontmatter and embeds it in the body. INoteStore gains a binary
create and a browse URL, so the raw page can link to the pictures. The
page takes pictures from a file picker (camera on phones) or from paste,
resized in the browser to 1600px.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
k.renner merged commit 53c03a8e53 into main 2026-09-25 07:55:43 +00:00
k.renner deleted branch feat/fact-images 2026-09-25 07:55:43 +00:00
Sign in to join this conversation.