#!/usr/bin/env sh set -eu : "${PDFSCRIBE_API_BASE:?set to https://api.pdfscribe.ai/v1}" : "${PDFSCRIBE_API_KEY:?set a scoped bearer key}" : "${PDFSCRIBE_FILE:?set a PDF or image path}" command -v jq >/dev/null poll_timeout=${PDFSCRIBE_POLL_TIMEOUT_SECONDS:-300} case "$poll_timeout" in ''|*[!0-9]*) echo 'PDFSCRIBE_POLL_TIMEOUT_SECONDS must be 1 to 3600' >&2; exit 1;; esac if [ "$poll_timeout" -lt 1 ] || [ "$poll_timeout" -gt 3600 ]; then echo 'PDFSCRIBE_POLL_TIMEOUT_SECONDS must be 1 to 3600' >&2; exit 1; fi request_timeout=30 size=$(wc -c < "$PDFSCRIBE_FILE" | tr -d ' ') content_type=${PDFSCRIBE_CONTENT_TYPE:-application/pdf} upload_idempotency_key="quickstart-upload-$(date +%s)-$$" api() { if curl -fs --globoff --max-time "$request_timeout" -H "Authorization: Bearer $PDFSCRIBE_API_KEY" "$@"; then return 0; else curl_status=$?; fi if [ "$curl_status" -eq 28 ] && [ "${polling_budget_limited:-false}" = true ]; then printf 'Polling timed out; resume checking the existing extraction ID: %s\n' "$extraction_id" >&2 else echo 'API request failed; check the existing extraction before retrying.' >&2 fi return "$curl_status" } create=$(api -H 'Content-Type: application/json' -H "Idempotency-Key: $upload_idempotency_key" -d "{\"content_type\":\"$content_type\",\"size_bytes\":$size}" "$PDFSCRIBE_API_BASE/uploads") url=$(printf %s "$create" | jq -r '.upload.url') method=$(printf %s "$create" | jq -r '.upload.method') upload_id=$(printf %s "$create" | jq -r '.id') # Escape every value for curl config, keeping signed URLs out of process arguments. # The bearer key is never forwarded to the signed storage destination. printf %s "$create" | jq -r --arg file "$PDFSCRIBE_FILE" ' "url = " + (.upload.url | @json), "request = " + (.upload.method | @json), "upload-file = " + ($file | @json), (.upload.headers | to_entries[] | .key as $key | .value[] | "header = " + (($key + ": " + .) | @json)) ' | curl -fs --globoff --max-time 30 --config - >/dev/null || { echo 'Signed upload failed.' >&2; exit 1; } api -X POST "$PDFSCRIBE_API_BASE/uploads/$upload_id/complete" >/dev/null idempotency_key="quickstart-$(date +%s)-$$" job=$(api -H 'Content-Type: application/json' -H "Idempotency-Key: $idempotency_key" -d "{\"upload_id\":\"$upload_id\",\"mode\":\"ocr\",\"pages\":\"all\",\"output\":{\"layout\":\"ordered\",\"include\":[\"text\",\"tables\"],\"table_format\":\"markdown\",\"confidence\":\"block\"}}" "$PDFSCRIBE_API_BASE/extractions") extraction_id=$(printf %s "$job" | jq -r .id) printf 'Accepted extraction ID: %s\n' "$extraction_id" >&2 deadline=$(( $(date +%s) + poll_timeout )) while :; do remaining=$(( deadline - $(date +%s) )) if [ "$remaining" -le 0 ]; then printf 'Polling timed out; resume checking the existing extraction ID: %s\n' "$extraction_id" >&2; exit 1; fi request_timeout=$remaining polling_budget_limited=true if [ "$request_timeout" -gt 30 ]; then request_timeout=30; polling_budget_limited=false; fi status=$(api "$PDFSCRIBE_API_BASE/extractions/$extraction_id") state=$(printf %s "$status" | jq -r .status) case "$state" in succeeded|partially_succeeded) break;; failed|cancelled|expired) printf 'Extraction ended with status: %s\n' "$state" >&2; exit 1;; esac sleep 1 done polling_budget_limited=false request_timeout=30 api "$PDFSCRIBE_API_BASE/extractions/$extraction_id/result?view=ordered&include=text,tables&table_format=markdown&confidence=block" | jq . api "$PDFSCRIBE_API_BASE/credits" | jq . api "$PDFSCRIBE_API_BASE/usage?page=1" | jq .