Go app for capturing and archiving HSA-eligible receipts: OIDC/PKCE auth against Authelia, SQLite storage with dual-write (filesystem + DB blob), mobile-first upload, and DB export. Adds AI receipt classification: a config.json catalog of people and categories (seeded into the DB on startup), a prompt builder that derives name-order/initial variants from the data (with same-surname ambiguity handling), and an Anthropic tool-use client behind POST /classify. Tests run against a mock endpoint; a live integration test is env-gated to the cheapest model. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
2.1 KiB
Bash
47 lines
2.1 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
IMG=/home/jm/Downloads/receipt.jpeg
|
|
B64=$(base64 -w0 "$IMG")
|
|
|
|
OUT=response.json
|
|
|
|
curl -s https://api.anthropic.com/v1/messages \
|
|
-H "x-api-key: $CLAUDE_API_KEY" \
|
|
-H "anthropic-version: 2023-06-01" \
|
|
-H "content-type: application/json" \
|
|
-o "$OUT" \
|
|
-d @- <<EOF
|
|
{
|
|
"model": "claude-opus-4-8",
|
|
"max_tokens": 1024,
|
|
"messages": [
|
|
{
|
|
"role": "user",
|
|
"content": [
|
|
{
|
|
"type": "image",
|
|
"source": { "type": "base64", "media_type": "image/jpeg", "data": "$B64" }
|
|
},
|
|
{
|
|
"type": "text",
|
|
"text": "Analyze this receipt and return ONLY a JSON object, no prose, with these fields:\n- \"person\": one of exactly \"jean-michel tremblay\", \"lynna nguyen\", or \"could not fetch\" if the name is absent or matches neither. The first and last name may appear in any order (e.g. \"Tremblay Jean-Michel\" or \"Nguyen, Lynna\"), possibly with a middle initial or accents; match on the name regardless of order or formatting.\n- \"category\": one of exactly \"pharmacy\", \"dental\", \"medical\", or \"other\".\n- \"date\": the receipt date as YYYY-MM-DD, or \"could not fetch\". Today is 2026-06-12, and the receipt date is usually within the last year or two of that (it may be a backfilled older receipt). The year is the last component; if it is only two digits, expand it to a year near the present (20YY within about 2 years of today), never far in the past or future. This is a US receipt, so read ambiguous numeric dates as MM-DD-YY.\n- \"amount\": the total as a plain number string (e.g. \"42.50\"), or \"could not fetch\"."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
echo "Raw response saved to $OUT"
|
|
jq -r '.content[0].text' "$OUT"
|
|
|
|
# Cost — Opus 4.8: $5/M input, $25/M output
|
|
jq -r '
|
|
.usage as $u
|
|
| ($u.input_tokens // 0) as $in
|
|
| ($u.output_tokens // 0) as $out
|
|
| ($in * 5 / 1000000) as $cin
|
|
| ($out * 25 / 1000000) as $cout
|
|
| "\n--- usage ---\ninput: \($in) tok $\($cin * 10000 | round / 10000)\noutput: \($out) tok $\($cout * 10000 | round / 10000)\ntotal: $\(($cin + $cout) * 10000 | round / 10000)"
|
|
' "$OUT"
|