hsa-app/call_claude.sh
Jean-Michel Tremblay 8b7252dad4 Initial commit: HSA receipt tracker
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>
2026-06-17 21:40:12 -04:00

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"