Reprocess AI Analysis SOP

Standard Operating Procedure for re-triggering AI analysis on calls that have already been processed or failed.

Prerequisites

  • AWS CLI configured with appropriate profile (e.g., --profile rc)
  • Access to DynamoDB and S3 in the target region

Environment Configuration

EnvironmentRegionConfig TableAnalysis TableS3 Bucket
testus-west-2call-analytics-test-call-analysis-config-us-west-2call-analytics-test-call-analysis-us-west-2call-analytics-test-recordings-us-west-2
produs-east-1call-analytics-prod-call-analysis-config-us-east-1call-analytics-prod-call-analysis-us-east-1call-analytics-prod-recordings-us-east-1

How AI Analysis Reprocessing Works

The ai-analysis-processor Lambda checks for existing analysis before processing:

  1. Queries call-analysis table by telephonySessionId
  2. If s3AnalysisPath exists and is non-empty → SKIP (already processed)
  3. If s3AnalysisPath is missing or empty → PROCESS (continue with analysis)

To reprocess a call, you must:

  1. Remove s3AnalysisPath from DynamoDB
  2. Re-upload the transcript file to S3 (triggers EventBridge → SQS → Lambda)

Step-by-Step Procedure

Step 1: Verify Call Status

# Check current analysis status
aws dynamodb get-item \
  --profile rc \
  --region us-west-2 \
  --table-name call-analytics-test-call-analysis-us-west-2 \
  --key '{"telephonySessionId": {"S": "SESSION_ID_HERE"}}' \
  --projection-expression "s3AnalysisPath, s3TranscriptPath, aiAnalysisCompleted, aiAnalysisStarted, callResult, recordingAvailable" \
  --output json

Check these fields:

  • callResult - If "Missed", call has no recording and cannot be analyzed
  • recordingAvailable - Must be true for analysis to work
  • s3TranscriptPath - Must exist to reprocess
  • s3AnalysisPath - If present, analysis already exists

Step 2: Remove s3AnalysisPath

aws dynamodb update-item \
  --profile rc \
  --region us-west-2 \
  --table-name call-analytics-test-call-analysis-us-west-2 \
  --key '{"telephonySessionId": {"S": "SESSION_ID_HERE"}}' \
  --update-expression "REMOVE s3AnalysisPath"

Step 3: Re-upload Transcript to Trigger EventBridge

# Get the transcript path from DynamoDB output (s3TranscriptPath field)
# Example: orangeTheory/193365026/2025/12/09/transcripts/193365026-sa0d7c410eb431z19b0515b005z1852d680000/transcription.json

# Download transcript
aws s3 cp \
  "s3://call-analytics-test-recordings-us-west-2/TRANSCRIPT_PATH_HERE" \
  /tmp/transcription.json \
  --profile rc --region us-west-2

# Re-upload to trigger EventBridge
aws s3 cp \
  /tmp/transcription.json \
  "s3://call-analytics-test-recordings-us-west-2/TRANSCRIPT_PATH_HERE" \
  --profile rc --region us-west-2

Step 4: Monitor Processing

EventBridge has a ~1 minute delay before the SQS message is delivered.

# Check Lambda logs
aws logs tail "/aws/lambda/call-analytics-test-ai-analysis-processor-ts-us-west-2" \
  --profile rc --region us-west-2 \
  --since 5m --format short | grep -E "SESSION_ID|SUCCESS|ERROR|complete"

Step 5: Verify Completion

aws dynamodb get-item \
  --profile rc \
  --region us-west-2 \
  --table-name call-analytics-test-call-analysis-us-west-2 \
  --key '{"telephonySessionId": {"S": "SESSION_ID_HERE"}}' \
  --projection-expression "s3AnalysisPath, aiAnalysisCompleted" \
  --output json

Expected result:

{
  "Item": {
    "s3AnalysisPath": { "S": "orangeTheory/.../ai-summary.json" },
    "aiAnalysisCompleted": { "BOOL": true }
  }
}

Batch Reprocessing

For multiple calls, create a script:

#!/bin/bash
# reprocess-calls.sh

PROFILE="rc"
REGION="us-west-2"
TABLE="call-analytics-test-call-analysis-us-west-2"
BUCKET="call-analytics-test-recordings-us-west-2"

SESSION_IDS=(
  "s-a0d7c410eb431z19b0515b005z1852d680000"
  "s-another-session-id"
)

for SESSION_ID in "${SESSION_IDS[@]}"; do
  echo "Processing: $SESSION_ID"

  # Get transcript path
  TRANSCRIPT_PATH=$(aws dynamodb get-item \
    --profile $PROFILE --region $REGION \
    --table-name $TABLE \
    --key "{\"telephonySessionId\": {\"S\": \"$SESSION_ID\"}}" \
    --projection-expression "s3TranscriptPath" \
    --output json | jq -r '.Item.s3TranscriptPath.S')

  if [ "$TRANSCRIPT_PATH" == "null" ] || [ -z "$TRANSCRIPT_PATH" ]; then
    echo "  SKIP: No transcript path found"
    continue
  fi

  # Remove s3AnalysisPath
  aws dynamodb update-item \
    --profile $PROFILE --region $REGION \
    --table-name $TABLE \
    --key "{\"telephonySessionId\": {\"S\": \"$SESSION_ID\"}}" \
    --update-expression "REMOVE s3AnalysisPath"

  # Re-upload transcript
  aws s3 cp "s3://$BUCKET/$TRANSCRIPT_PATH" /tmp/transcript.json --profile $PROFILE --region $REGION
  aws s3 cp /tmp/transcript.json "s3://$BUCKET/$TRANSCRIPT_PATH" --profile $PROFILE --region $REGION

  echo "  DONE: Triggered reprocessing"
  sleep 2  # Avoid rate limiting
done

Troubleshooting

Error: "Missing required DynamoDB fields: inference_config"

The client config is missing inference_config. Add it:

aws dynamodb update-item \
  --profile rc --region us-west-2 \
  --table-name call-analytics-test-call-analysis-config-us-west-2 \
  --key '{"client_id": {"S": "CLIENT_ID_HERE"}}' \
  --update-expression "SET inference_config = :ic" \
  --expression-attribute-values '{":ic": {"M": {"temperature": {"N": "1.0"}, "maxTokens": {"N": "16000"}}}}'

Error: "Kimi JSON truncation / Unexpected end of JSON input"

maxTokens is too low for Kimi thinking model. Update to 16000:

aws dynamodb update-item \
  --profile rc --region us-west-2 \
  --table-name call-analytics-test-call-analysis-config-us-west-2 \
  --key '{"client_id": {"S": "CLIENT_ID_HERE"}}' \
  --update-expression "SET inference_config.maxTokens = :mt" \
  --expression-attribute-values '{":mt": {"N": "16000"}}'

Error: "not authorized to perform: bedrock:InvokeModel"

IAM permissions missing for the region. Check lib/stacks/iam-stack.ts for Bedrock permissions.

Call has callResult="Missed" or recordingAvailable=false

Missed calls have no recording and cannot be analyzed. This is expected behavior.

SQS message stuck (ApproximateNumberOfMessagesNotVisible > 0)

Check visibility timeout (default: 960s / 16 minutes). Wait for timeout to expire or check DLQ for failed messages.

aws sqs get-queue-attributes \
  --profile rc --region us-west-2 \
  --queue-url "https://sqs.us-west-2.amazonaws.com/ACCOUNT_ID/call-analytics-test-ai-analysis-queue-us-west-2" \
  --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible