Cloud infrastructure
Every AWS resource + external API the Zapcopy OCR pipeline touches. Region us-east-1, as of 2026-04-20.
Lambdas
| ID | Purpose | Handler | Flows | URL |
|---|---|---|---|---|
| presign_url_lambda | Returns a presigned PUT URL for photo upload into qr-uploads-sup/incoming/. | qr_reader_v1/(presign handler).py | single-photocollection | https://n5amzilx7csdm4u47ej7s6byqi0njobn.lambda-url.us-east-1.on.aws/ |
| extended_lambda_ocr | Rekognition moderation (80 % threshold) → if approved, Gemini OCR → writes ocr/<uuid>.txt. | qr_reader_v1/EXTENDED_LAMBDA_OCR.py | single-photocollection | https://4x23xiiev3kn57ovg5n3ujfmqu0zeozb.lambda-url.us-east-1.on.aws/ |
| presign_frames_lambda | Bulk presigns PUT URLs for every extracted frame in a video. | qr_reader_v1/(presign_frames handler).py | video | https://4tpxhyvalswtk4s3gcaytkdxkq0fjnux.lambda-url.us-east-1.on.aws/ |
| frame_ocr_lambda | OCR a single frame with Gemini; persists result JSON into <videoId>/results/. | qr_reader_v1/frame_ocr_lambda.py | video | https://tr5xlblh3mqdarwo4cole77wm40vxlwn.lambda-url.us-east-1.on.aws/ |
| aggregator_lambda | Concatenates per-frame results into combined.txt; then fans out to the selected stitching branch. | qr_reader_v1/aggregator_lambda.py | video | https://eld2oaakylpwvtd7kk5c4pptpa0xunsw.lambda-url.us-east-1.on.aws/ |
| video_ocr_polishing_lambda | Polishes combined.txt via Gemini with a structured-output JSON schema; writes final.txt. | qr_reader_v1/video_ocr_polishing_lambda_rest.py | video | https://63mgj7wm4pf4xnvnakt7wdsium0udcih.lambda-url.us-east-1.on.aws/ |
| python_stitcher_lambda | Deterministic Python stitching fallback (used by pythonOnly and pythonThenGemini pipeline modes). | qr_reader_v1/improved_python_stitcher.py | video | https://mnbqic443mgj3c5arei37e5miy0wauoq.lambda-url.us-east-1.on.aws/ |
| video_ocr_background_processor | Long-running orchestration for background video OCR; coordinates frame fan-out, aggregation, polish, and push notification on completion. | qr_reader_v1/video_ocr_background_processor_lambda.py | video | https://msdpenazezims5zws3irlss3ra0kjibx.lambda-url.us-east-1.on.aws/ |
| push_send_lambda | Looks up the user's APNS device token in DynamoDB and publishes a VideoOCRCompleteRemote notification via SNS. | qr_reader_v1/push_send_lambda.py | video | (internal; invoked via boto3 from background_processor) |
| full_video_ocr_lambda | Legacy foreground video OCR endpoint — bypassed when background processing is enabled (current default). | qr_reader_v1/(full_video_ocr handler).py | https://uiubxcbyfyvkj4bkmlocc5fmae0prfol.lambda-url.us-east-1.on.aws/ | |
| video_converter_lambda | Transcodes .mov → .mp4 for downstream consumption when needed. | qr_reader_v1/(video_converter handler).py | video | https://iwjtl2p7ai5mcjhpwsq7oaf3ri0fsrri.lambda-url.us-east-1.on.aws/ |
| moderation_ocr_lambda_v2 | v2 of extended_lambda_ocr. Rekognition moderation unchanged. Gemini OCR now returns {ocr_text, notes} via responseSchema. S3 OCR output under v2/ocr/. | qr_reader_v1/lambdas/v2/moderation_ocr_v2.py | single-photocollection | https://ztcbkrrhtk5sh2stxnj2qmjc5u0pciff.lambda-url.us-east-1.on.aws/ |
| frame_ocr_lambda_v2 | v2 of frame_ocr_lambda. Gemini returns {text} via responseSchema; result docs under v2/video-ocr/. | qr_reader_v1/lambdas/v2/frame_ocr_v2.py | video | https://p4b5z3mdwqexkm6pcmpoyerqz40axqcl.lambda-url.us-east-1.on.aws/ |
| video_ocr_polishing_lambda_v2 | v2 of video_ocr_polishing_lambda. Gemini returns {stitched_response, additional_notes} via responseSchema. Removes v1's fence-stripping fallback that silently returned raw text. | qr_reader_v1/lambdas/v2/video_polish_v2.py | video | https://bk2c62xvi4pinbjh4ihrgmhxiu0tlfgg.lambda-url.us-east-1.on.aws/ |
| video_aggregator_lambda_v2 | v2 of aggregator_lambda. Namespace v2/video-ocr/, calls v2 polish Lambda, and fires push-send (fire-and-forget) when polish succeeds AND the POST body carries userId. Also handles DELETE {videoId} for recursive v2-prefix cleanup (hard-guarded). | qr_reader_v1/lambdas/v2/video_aggregator_v2.py | video | https://rhlegttwkjqgxihkypa3ogqigm0kvxlh.lambda-url.us-east-1.on.aws/ |
S3 buckets
- qr-uploads-supSingle-photo uploads + photo OCR result storageKeys
- · incoming/<uuid>.jpg
- · ocr/<uuid>.txt
- qr-video-ocr-framesPer-frame OCR artifacts for the background-video pipelineKeys
- · <videoId>/frames/frame_<nnnnn>.jpg
- · <videoId>/results/frame_<nnnnn>.json
- · <videoId>/combined.txt
- · <videoId>/final.txt
Rekognition
API:
detect_moderation_labelsThreshold: 80%
Blocked labels
Explicit NudityNudityGraphic ViolenceViolenceDrugsTobaccoAlcoholGamblingHate SymbolsSelf Injury
Fallback on reject
s3.delete(objectKey) — the uploaded image is scrubbed if moderation rejects it.
DynamoDB
- flash-copy-usersPK
userId· GSIsUserCreditsIndexUser records, subscription state, credit balance, APNS device tokens.
SNS → APNS
Topic ARN:
(masked — arn:aws:sns:us-east-1:***:qr-beam-video-complete)Platform: APNS
Notification:
VideoOCRCompleteRemoteExternal (non-AWS)
- gemini · Googlegemini-2.5-flashhttps://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
Explicitly not used
AWS BedrockAWS TextractAWS ECS / FargateAWS SQSAWS Step FunctionsAWS KinesisAWS EC2AWS RDS
Verified by grep boto3.client over the Lambda sources — references elsewhere are in vendored SDK packages, never called from handler code.