#!/usr/bin/env bash
# Transcribe an Arabic recording with Kalemio; save JSON and SRT beside it.
#   export KALEMIO_API_KEY='YOUR_API_KEY'
#   bash kalemio_quickstart.sh conversation.m4a
# Needs curl and jq.
set -euo pipefail
API="${KALEMIO_API_BASE:-https://kalemio.app}"
FILE="$1"
AUTH="Authorization: Bearer $KALEMIO_API_KEY"
# The same file always sends the same key, so running this again after an
# interruption returns the first job instead of starting and billing another.
# A second argument, such as retry1, makes a new key to transcribe it afresh.
HASH=$( (sha256sum "$FILE" 2>/dev/null || shasum -a 256 "$FILE") | cut -c1-32)
KEY="quickstart-$HASH${2:+-$2}"
# Responses go to a file, which curl empties before each retry.
BODY=$(mktemp) HEADERS=$(mktemp)
trap 'rm -f "$BODY" "$HEADERS"' EXIT

# Rate limits and server errors are retried; the Free plan's own limits don't clear soon.
for WAIT in 1 2 4 8 0; do
  STATUS=$(curl -sS -D "$HEADERS" -o "$BODY" -w '%{http_code}' \
    "$API/v1/transcriptions" -H "$AUTH" -H "Idempotency-Key: $KEY" \
    -F "file=@$FILE" -F speakers=auto)
  case $STATUS in
    429) [[ $(jq -r '.code // ""' "$BODY") != free_* ]] || break ;;
    5??) ;;
    *) break ;;
  esac
  [ "$WAIT" != 0 ] || break
  AFTER=$(tr -d '\r' <"$HEADERS" | awk 'tolower($1) == "retry-after:" { print $2 }')
  sleep "${AFTER:-$WAIT}"
done
if [ "$STATUS" = 402 ]; then
  echo "Not enough minutes: $(jq -r .error "$BODY") Nothing was charged." >&2
  echo "Add a plan or minutes at $API/developers/portal/ and run this again." >&2
  exit 1
elif [ "$STATUS" != 202 ]; then
  echo "Upload refused ($STATUS): $(jq -r .error "$BODY")" >&2
  exit 1
fi
JOB_ID=$(jq -r .id "$BODY")
echo "Job $JOB_ID accepted ($(jq -r .processing "$BODY") processing)"

# Fetches this job's status, or a download, into $BODY; stops with the API's reason.
get() {
  : >"$BODY"
  curl -sS --fail-with-body --retry 4 -H "$AUTH" -o "$BODY" \
    "$API/v1/transcriptions/$JOB_ID$1" && return
  REASON=$(jq -r '.error // empty' "$BODY" 2>/dev/null || true)
  [ -z "$REASON" ] || echo "Request failed: $REASON" >&2
  exit 1
}

# Free plan jobs can wait in a queue for a while: check less often, up to 30 s.
DELAY=3
while :; do
  sleep "$DELAY"
  get ""
  case $(jq -r .status "$BODY") in
    completed) break ;;
    failed) echo "Job $JOB_ID failed: $(jq -r .error "$BODY")" >&2; exit 1 ;;
  esac
  DELAY=$(( DELAY < 15 ? DELAY * 2 : 30 ))
done

NAME="${FILE%.*}"
get /result; cp "$BODY" "$NAME.json"
get /srt; cp "$BODY" "$NAME.srt"
echo "Saved $NAME.json and $NAME.srt"

