From 2b9648dd1a7e07cb80dfdca3d9d2fcebd5dd20cc Mon Sep 17 00:00:00 2001 From: Bryce Date: Wed, 27 May 2026 10:12:45 -0700 Subject: [PATCH] new glimpse approach --- .terraform.tfstate.lock.info | 1 + code/main.py | 94 +++++- invoke_lambda.sh | 26 ++ main.tf | 27 +- prod.tfvars | 1 + terraform.tfstate.d/test/terraform.tfstate | 313 ++++++++++++++++++ .../test/terraform.tfstate.backup | 313 ++++++++++++++++++ test.tfvars | 1 + variables.tf | 15 + 9 files changed, 768 insertions(+), 23 deletions(-) create mode 100644 .terraform.tfstate.lock.info create mode 100755 invoke_lambda.sh create mode 100644 prod.tfvars create mode 100644 terraform.tfstate.d/test/terraform.tfstate create mode 100644 terraform.tfstate.d/test/terraform.tfstate.backup create mode 100644 test.tfvars create mode 100644 variables.tf diff --git a/.terraform.tfstate.lock.info b/.terraform.tfstate.lock.info new file mode 100644 index 0000000..ead98c6 --- /dev/null +++ b/.terraform.tfstate.lock.info @@ -0,0 +1 @@ +{"ID":"842a4264-8857-6f39-d95a-cbc58d58337d","Operation":"OperationTypePlan","Info":"","Who":"noti@pop-os","Version":"1.15.1","Created":"2026-05-27T17:06:58.450709065Z","Path":"terraform.tfstate"} \ No newline at end of file diff --git a/code/main.py b/code/main.py index 64351e7..2f2d613 100755 --- a/code/main.py +++ b/code/main.py @@ -2,7 +2,6 @@ import base64 import json import os -import re import urllib.request from dotenv import load_dotenv @@ -24,29 +23,81 @@ def slurp_file(filename): return file.read() -BASE_PROMPT="""You are an invoice extraction assistant. Your job is to read PDF documents and extract all invoice and credit note details into structured JSON. +BASE_PROMPT="""You are an invoice extraction assistant. Your job is to read PDF documents and extract all invoice and credit note details. DOCUMENT TYPES YOU MAY ENCOUNTER: 1. **Single Invoice** — one invoice with line items, totals, dates, etc. 2. **Credit Note** — similar to an invoice but represents a credit/refund. Extract it the same way; the total will be positive (the credit amount). -3. **Statement / Summary** — a document listing multiple invoices or credits in a table or list format. Each row or entry represents a separate invoice/credit. Extract EACH one as a separate object in the output array. +3. **Statement / Summary** — a document listing multiple invoices or credits in a table or list format. Each row or entry represents a separate invoice/credit. 4. **Mixed** — a document containing both invoices and credits. EXTRACTION RULES: -- Extract EVERY invoice or credit you can find. If the document is a statement listing 10 invoices, return all 10. +- Extract EVERY invoice or credit you can find. If the document is a statement listing 10 invoices, include all 10 in the invoices array. - **customer_identifier**: The name of the customer/buyer. Look for "Bill To", "Customer", "Sold To", or the company name at the top. - **vendor_identifier**: The name of the vendor/seller. Look for "From", "Vendor", "Supplier", letterhead, or the company issuing the document. - **date**: The invoice date in ISO 8601 format (YYYY-MM-DD). If multiple dates exist, use the invoice date, not the due date or statement period. - **invoice_number**: The unique invoice or credit note number. Look for labels like "Invoice #", "Inv No", "Credit Note #", "Reference", "Doc #". - **account_number**: The customer's account number if present. Not required — omit if not found. - **total**: The total amount as a decimal string (e.g., "1234.56"). Use the grand total or amount due. For credits, use the credit amount as a positive number. Numbers in parentheses indicate credits — extract them as positive values. -- **explanation**: Only use this when you cannot find any valid invoices. Provide a detailed reason (e.g., "document is blank", "PDF contains only images with no extractable text", "document is a cover letter with no invoice data"). IMPORTANT: - Do NOT skip entries because some fields are missing. Extract what you can. -- For statements/summaries, each row in an invoice table is a separate invoice entry. -- If OCR fails completely and no text can be extracted at all, return an array with one object containing only the explanation field. -- Your FINAL response must be ONLY a JSON array. Do NOT wrap it in markdown code blocks. Do NOT add any prose before or after the JSON.""" +- For statements/summaries, each row in an invoice table is a separate entry in the invoices array. +- If OCR fails completely and no text can be extracted at all, set the explanation field to indicate why.""" + +INVOICE_TOOL = { + "type": "function", + "function": { + "name": "parsed_invoices", + "description": "Record all extracted invoices and credit notes from the document. Include every invoice found in the invoices array.", + "parameters": { + "type": "object", + "properties": { + "invoices": { + "description": "Array of all invoices and credit notes extracted from the document. Include every one you find.", + "type": "array", + "items": { + "type": "object", + "properties": { + "customer_identifier": { + "description": "The customer's name. e.g., ABC Corporation, Microsoft, etc.", + "type": "string" + }, + "vendor_identifier": { + "description": "The vendor's name", + "type": "string" + }, + "date": { + "description": "Invoice date in ISO 8601 format (YYYY-MM-DD).", + "type": "string", + "format": "date" + }, + "invoice_number": { + "description": "Unique invoice number for the transaction.", + "type": "string" + }, + "account_number": { + "description": "Customer's account number associated with the invoice. Not always present on the invoice.", + "type": "string" + }, + "total": { + "description": "Total amount of the invoice, including taxes and fees. It should be a decimal number as a string.", + "type": "string", + "pattern": "^\\d+(\\.\\d{1,2})?$" + } + }, + "required": ["customer_identifier", "vendor_identifier", "date", "invoice_number", "total"], + "additionalProperties": False + } + }, + "explanation": { + "description": "Only use this when you cannot find any valid invoices. Provide a detailed reason (e.g., 'document is blank', 'PDF contains only images with no extractable text', 'document is a cover letter with no invoice data').", + "type": "string" + } + } + } + } +} def analyze_pdf(pdf_path): @@ -80,12 +131,18 @@ def analyze_pdf(pdf_path): ], }, ], + tools=[INVOICE_TOOL], ) - text = response.choices[0].message.content - match = re.search(r'```(?:json)?\s*\n(.*?)\n```', text, re.DOTALL) - if match: - text = match.group(1) - return text + + message = response.choices[0].message + + if message.tool_calls: + for tool_call in message.tool_calls: + if tool_call.function.name == "parsed_invoices": + data = json.loads(tool_call.function.arguments) + return data.get("invoices", []) + + return [] def analyze_url(url): @@ -98,6 +155,11 @@ def analyze_url(url): def handler(event, context): print(event) - url = event['url'] - print("URL IS", url) - return analyze_url(url) \ No newline at end of file + if "pdf_base64" in event: + pdf_path = "/tmp/invoice.pdf" + with open(pdf_path, "wb") as f: + f.write(base64.b64decode(event["pdf_base64"])) + return analyze_pdf(pdf_path) + if "url" in event: + return analyze_url(event["url"]) + raise ValueError("event must contain 'url' or 'pdf_base64'") \ No newline at end of file diff --git a/invoke_lambda.sh b/invoke_lambda.sh new file mode 100755 index 0000000..e160c20 --- /dev/null +++ b/invoke_lambda.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +PDF_PATH="${1:-tests/SWCPI25011315283.pdf}" +ENVIRONMENT="${2:-test}" + +if [ ! -f "$PDF_PATH" ]; then + echo "Error: PDF file not found: $PDF_PATH" + exit 1 +fi + +FUNCTION_NAME="glimpse2-${ENVIRONMENT}" +PAYLOAD_FILE=$(mktemp) +python3 -c "import base64, json, sys; json.dump({'pdf_base64': base64.b64encode(open(sys.argv[1], 'rb').read()).decode()}, open(sys.argv[2], 'w'))" "$PDF_PATH" "$PAYLOAD_FILE" + +echo "Invoking ${FUNCTION_NAME} with ${PDF_PATH}..." +aws lambda invoke \ + --function-name "$FUNCTION_NAME" \ + --payload file://"$PAYLOAD_FILE" \ + --cli-binary-format raw-in-base64-out \ + /tmp/lambda_response.json + +rm -f "$PAYLOAD_FILE" + +echo "Response:" +python3 -m json.tool /tmp/lambda_response.json 2>/dev/null || cat /tmp/lambda_response.json diff --git a/main.tf b/main.tf index 3391ef1..476c433 100644 --- a/main.tf +++ b/main.tf @@ -1,3 +1,16 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "aws" { + region = var.region +} + data "aws_iam_policy_document" "assume_role" { statement { effect = "Allow" @@ -13,11 +26,11 @@ data "aws_iam_policy_document" "assume_role" { resource "null_resource" "pip_install" { triggers = { - shell_hash = "${sha256(file("${path.module}/requirements.txt"))}" + shell_hash = "${sha256(file("${path.module}/pyproject.toml"))}" } provisioner "local-exec" { - command = "python3 -m pip install -r requirements.txt -t ${path.module}/layer/python" + command = "uv pip compile ${path.module}/pyproject.toml --python 3.11 --no-header -o /tmp/layer-requirements.txt && uv pip install -r /tmp/layer-requirements.txt --python 3.11 -t ${path.module}/layer/python" } } @@ -29,7 +42,7 @@ data "archive_file" "layer" { } resource "aws_lambda_layer_version" "layer" { - layer_name = "openai-layer" + layer_name = "openai-layer-${local.env}" filename = data.archive_file.layer.output_path source_code_hash = data.archive_file.layer.output_base64sha256 compatible_runtimes = ["python3.11"] @@ -38,7 +51,7 @@ resource "aws_lambda_layer_version" "layer" { resource "aws_iam_role" "iam_for_lambda" { - name = "glimpse2" + name = "glimpse2-${local.env}" assume_role_policy = data.aws_iam_policy_document.assume_role.json } @@ -52,11 +65,11 @@ resource "aws_lambda_function" "test_lambda" { # If the file is not in the current working directory you will need to include a # path.module in the filename. filename = "lambda_function_payload.zip" - function_name = "glimpse2" + function_name = "glimpse2-${local.env}" role = aws_iam_role.iam_for_lambda.arn handler = "main.handler" memory_size = 512 - timeout = 30 + timeout = 60 source_code_hash = data.archive_file.lambda.output_base64sha256 layers = [aws_lambda_layer_version.layer.arn] @@ -65,7 +78,7 @@ resource "aws_lambda_function" "test_lambda" { environment { variables = { - foo = "bar" + environment = local.env } } } diff --git a/prod.tfvars b/prod.tfvars new file mode 100644 index 0000000..23a817b --- /dev/null +++ b/prod.tfvars @@ -0,0 +1 @@ +environment = "prod" diff --git a/terraform.tfstate.d/test/terraform.tfstate b/terraform.tfstate.d/test/terraform.tfstate new file mode 100644 index 0000000..c73ee41 --- /dev/null +++ b/terraform.tfstate.d/test/terraform.tfstate @@ -0,0 +1,313 @@ +{ + "version": 4, + "terraform_version": "1.15.1", + "serial": 8, + "lineage": "d233b79d-da3f-cd9d-4b62-af1c850901ee", + "outputs": {}, + "resources": [ + { + "mode": "data", + "type": "archive_file", + "name": "lambda", + "provider": "provider[\"registry.terraform.io/hashicorp/archive\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "exclude_symlink_directories": null, + "excludes": null, + "id": "9d3e0e20184ca740cf3ea4340de29c39affb671d", + "output_base64sha256": "y9M2eCZjnOi+6H60vC4z+HW95OP9GVC0Icw3Yc3xIvU=", + "output_base64sha512": "YbENaC7DYFAI6nJLrnOR99yZx8zFjnboHpcQGRD0/MKuPi+B6oy6l4NsnFAekayBOWddxZquWHTcqZcx9LiCdQ==", + "output_file_mode": null, + "output_md5": "fcfa112d0c05b2a40c72445a7438b356", + "output_path": "lambda_function_payload.zip", + "output_sha": "9d3e0e20184ca740cf3ea4340de29c39affb671d", + "output_sha256": "cbd3367826639ce8bee87eb4bc2e33f875bde4e3fd1950b421cc3761cdf122f5", + "output_sha512": "61b10d682ec3605008ea724bae7391f7dc99c7ccc58e76e81e97101910f4fcc2ae3e2f81ea8cba97836c9c501e91ac8139675dc59aae5874dca99731f4b88275", + "output_size": 12212, + "source": [], + "source_content": null, + "source_content_filename": null, + "source_dir": "./code", + "source_file": null, + "type": "zip" + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + }, + { + "mode": "data", + "type": "archive_file", + "name": "layer", + "provider": "provider[\"registry.terraform.io/hashicorp/archive\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "exclude_symlink_directories": null, + "excludes": null, + "id": "b2027e85f6c1607a31456d9bab04adea560c124a", + "output_base64sha256": "dB5NITnNHiiWWQtFv9f3eYWRilrtiE60AJNMWRadSlA=", + "output_base64sha512": "YSSHtd8poCa26moOzdrQBJ8zuSK2L2N7XOIJq7KgDerdfbty2gPkcNi7Y/7jQ1UHP++Wft9vZO3P0zYO6T5tmA==", + "output_file_mode": null, + "output_md5": "777cb1543745e89136e2e9efe52b7dee", + "output_path": "./layer.zip", + "output_sha": "b2027e85f6c1607a31456d9bab04adea560c124a", + "output_sha256": "741e4d2139cd1e2896590b45bfd7f77985918a5aed884eb400934c59169d4a50", + "output_sha512": "612487b5df29a026b6ea6a0ecddad0049f33b922b62f637b5ce209abb2a00deadd7dbb72da03e470d8bb63fee34355073fef967edf6f64edcfd3360ee93e6d98", + "output_size": 7103838, + "source": [], + "source_content": null, + "source_content_filename": null, + "source_dir": "./layer", + "source_file": null, + "type": "zip" + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + }, + { + "mode": "data", + "type": "aws_iam_policy_document", + "name": "assume_role", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "2690255455", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"Service\": \"lambda.amazonaws.com\"\n }\n }\n ]\n}", + "minified_json": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"}}]}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "sts:AssumeRole" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + "lambda.amazonaws.com" + ], + "type": "Service" + } + ], + "resources": [], + "sid": "" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_role", + "name": "iam_for_lambda", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::695105795926:role/glimpse2-test", + "assume_role_policy": "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}", + "create_date": "2026-05-27T17:09:01Z", + "description": "", + "force_detach_policies": false, + "id": "glimpse2-test", + "inline_policy": [], + "managed_policy_arns": [], + "max_session_duration": 3600, + "name": "glimpse2-test", + "name_prefix": "", + "path": "/", + "permissions_boundary": "", + "tags": {}, + "tags_all": {}, + "unique_id": "AROA2DV4IW5LLMAWHIGZQ" + }, + "sensitive_attributes": [], + "identity_schema_version": 0, + "private": "bnVsbA==", + "dependencies": [ + "data.aws_iam_policy_document.assume_role" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lambda_function", + "name": "test_lambda", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "architectures": [ + "x86_64" + ], + "arn": "arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test", + "code_sha256": "y9M2eCZjnOi+6H60vC4z+HW95OP9GVC0Icw3Yc3xIvU=", + "code_signing_config_arn": "", + "dead_letter_config": [], + "description": "", + "environment": [ + { + "variables": { + "environment": "test" + } + } + ], + "ephemeral_storage": [ + { + "size": 512 + } + ], + "file_system_config": [], + "filename": "lambda_function_payload.zip", + "function_name": "glimpse2-test", + "handler": "main.handler", + "id": "glimpse2-test", + "image_config": [], + "image_uri": "", + "invoke_arn": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test/invocations", + "kms_key_arn": "", + "last_modified": "2026-05-27T17:11:46.000+0000", + "layers": [ + "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test:1" + ], + "logging_config": [ + { + "application_log_level": "", + "log_format": "Text", + "log_group": "/aws/lambda/glimpse2-test", + "system_log_level": "" + } + ], + "memory_size": 512, + "package_type": "Zip", + "publish": false, + "qualified_arn": "arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test:$LATEST", + "qualified_invoke_arn": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test:$LATEST/invocations", + "replace_security_groups_on_destroy": null, + "replacement_security_group_ids": null, + "reserved_concurrent_executions": -1, + "role": "arn:aws:iam::695105795926:role/glimpse2-test", + "runtime": "python3.11", + "s3_bucket": null, + "s3_key": null, + "s3_object_version": null, + "signing_job_arn": "", + "signing_profile_version_arn": "", + "skip_destroy": false, + "snap_start": [], + "source_code_hash": "y9M2eCZjnOi+6H60vC4z+HW95OP9GVC0Icw3Yc3xIvU=", + "source_code_size": 12212, + "tags": {}, + "tags_all": {}, + "timeout": 60, + "timeouts": null, + "tracing_config": [ + { + "mode": "PassThrough" + } + ], + "version": "$LATEST", + "vpc_config": [] + }, + "sensitive_attributes": [], + "identity_schema_version": 0, + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6NjAwMDAwMDAwMDAwLCJ1cGRhdGUiOjYwMDAwMDAwMDAwMH19", + "dependencies": [ + "aws_iam_role.iam_for_lambda", + "aws_lambda_layer_version.layer", + "data.archive_file.lambda", + "data.archive_file.layer", + "data.aws_iam_policy_document.assume_role", + "null_resource.pip_install" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lambda_layer_version", + "name": "layer", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test:1", + "code_sha256": "dB5NITnNHiiWWQtFv9f3eYWRilrtiE60AJNMWRadSlA=", + "compatible_architectures": [], + "compatible_runtimes": [ + "python3.11" + ], + "created_date": "2026-05-27T17:09:07.743+0000", + "description": "", + "filename": "./layer.zip", + "id": "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test:1", + "layer_arn": "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test", + "layer_name": "openai-layer-test", + "license_info": "", + "s3_bucket": null, + "s3_key": null, + "s3_object_version": null, + "signing_job_arn": "", + "signing_profile_version_arn": "", + "skip_destroy": false, + "source_code_hash": "dB5NITnNHiiWWQtFv9f3eYWRilrtiE60AJNMWRadSlA=", + "source_code_size": 7103838, + "version": "1" + }, + "sensitive_attributes": [], + "identity_schema_version": 0, + "private": "bnVsbA==", + "dependencies": [ + "data.archive_file.layer", + "null_resource.pip_install" + ] + } + ] + }, + { + "mode": "managed", + "type": "null_resource", + "name": "pip_install", + "provider": "provider[\"registry.terraform.io/hashicorp/null\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "5491774440303221650", + "triggers": { + "shell_hash": "84016380c6c240dd563a10e364ece2d65f4ad6c7313b2dd69cefbeb949fcfa4b" + } + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + } + ], + "check_results": null +} diff --git a/terraform.tfstate.d/test/terraform.tfstate.backup b/terraform.tfstate.d/test/terraform.tfstate.backup new file mode 100644 index 0000000..a9f8f5a --- /dev/null +++ b/terraform.tfstate.d/test/terraform.tfstate.backup @@ -0,0 +1,313 @@ +{ + "version": 4, + "terraform_version": "1.15.1", + "serial": 6, + "lineage": "d233b79d-da3f-cd9d-4b62-af1c850901ee", + "outputs": {}, + "resources": [ + { + "mode": "data", + "type": "archive_file", + "name": "lambda", + "provider": "provider[\"registry.terraform.io/hashicorp/archive\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "exclude_symlink_directories": null, + "excludes": null, + "id": "076a08927a351c0f32ee35bce706df144469e677", + "output_base64sha256": "JhTe97YTSvuFlvDFGzhFP+f6yE7Rn6HSp2Y1SYVlOVY=", + "output_base64sha512": "P1Z89ahd14HUlbP7q8yNoFmZPu6B9w95stgmbqEkpWdx1NhJwdiNN4iYDqdHJI/q6cdzE1xLkU8wxwyDIWZj+Q==", + "output_file_mode": null, + "output_md5": "5d9102792c60073f6c15da416babe408", + "output_path": "lambda_function_payload.zip", + "output_sha": "076a08927a351c0f32ee35bce706df144469e677", + "output_sha256": "2614def7b6134afb8596f0c51b38453fe7fac84ed19fa1d2a766354985653956", + "output_sha512": "3f567cf5a85dd781d495b3fbabcc8da059993eee81f70f79b2d8266ea124a56771d4d849c1d88d3788980ea747248feae9c773135c4b914f30c70c83216663f9", + "output_size": 12141, + "source": [], + "source_content": null, + "source_content_filename": null, + "source_dir": "./code", + "source_file": null, + "type": "zip" + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + }, + { + "mode": "data", + "type": "archive_file", + "name": "layer", + "provider": "provider[\"registry.terraform.io/hashicorp/archive\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "exclude_symlink_directories": null, + "excludes": null, + "id": "b2027e85f6c1607a31456d9bab04adea560c124a", + "output_base64sha256": "dB5NITnNHiiWWQtFv9f3eYWRilrtiE60AJNMWRadSlA=", + "output_base64sha512": "YSSHtd8poCa26moOzdrQBJ8zuSK2L2N7XOIJq7KgDerdfbty2gPkcNi7Y/7jQ1UHP++Wft9vZO3P0zYO6T5tmA==", + "output_file_mode": null, + "output_md5": "777cb1543745e89136e2e9efe52b7dee", + "output_path": "./layer.zip", + "output_sha": "b2027e85f6c1607a31456d9bab04adea560c124a", + "output_sha256": "741e4d2139cd1e2896590b45bfd7f77985918a5aed884eb400934c59169d4a50", + "output_sha512": "612487b5df29a026b6ea6a0ecddad0049f33b922b62f637b5ce209abb2a00deadd7dbb72da03e470d8bb63fee34355073fef967edf6f64edcfd3360ee93e6d98", + "output_size": 7103838, + "source": [], + "source_content": null, + "source_content_filename": null, + "source_dir": "./layer", + "source_file": null, + "type": "zip" + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + }, + { + "mode": "data", + "type": "aws_iam_policy_document", + "name": "assume_role", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "2690255455", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"Service\": \"lambda.amazonaws.com\"\n }\n }\n ]\n}", + "minified_json": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"}}]}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "sts:AssumeRole" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + "lambda.amazonaws.com" + ], + "type": "Service" + } + ], + "resources": [], + "sid": "" + } + ], + "version": "2012-10-17" + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + }, + { + "mode": "managed", + "type": "aws_iam_role", + "name": "iam_for_lambda", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:iam::695105795926:role/glimpse2-test", + "assume_role_policy": "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}", + "create_date": "2026-05-27T17:09:01Z", + "description": "", + "force_detach_policies": false, + "id": "glimpse2-test", + "inline_policy": [], + "managed_policy_arns": [], + "max_session_duration": 3600, + "name": "glimpse2-test", + "name_prefix": "", + "path": "/", + "permissions_boundary": "", + "tags": null, + "tags_all": {}, + "unique_id": "AROA2DV4IW5LLMAWHIGZQ" + }, + "sensitive_attributes": [], + "identity_schema_version": 0, + "private": "bnVsbA==", + "dependencies": [ + "data.aws_iam_policy_document.assume_role" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lambda_function", + "name": "test_lambda", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "architectures": [ + "x86_64" + ], + "arn": "arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test", + "code_sha256": "JhTe97YTSvuFlvDFGzhFP+f6yE7Rn6HSp2Y1SYVlOVY=", + "code_signing_config_arn": "", + "dead_letter_config": [], + "description": "", + "environment": [ + { + "variables": { + "environment": "test" + } + } + ], + "ephemeral_storage": [ + { + "size": 512 + } + ], + "file_system_config": [], + "filename": "lambda_function_payload.zip", + "function_name": "glimpse2-test", + "handler": "main.handler", + "id": "glimpse2-test", + "image_config": [], + "image_uri": "", + "invoke_arn": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test/invocations", + "kms_key_arn": "", + "last_modified": "2026-05-27T17:09:08.994+0000", + "layers": [ + "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test:1" + ], + "logging_config": [ + { + "application_log_level": "", + "log_format": "Text", + "log_group": "/aws/lambda/glimpse2-test", + "system_log_level": "" + } + ], + "memory_size": 512, + "package_type": "Zip", + "publish": false, + "qualified_arn": "arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test:$LATEST", + "qualified_invoke_arn": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:695105795926:function:glimpse2-test:$LATEST/invocations", + "replace_security_groups_on_destroy": null, + "replacement_security_group_ids": null, + "reserved_concurrent_executions": -1, + "role": "arn:aws:iam::695105795926:role/glimpse2-test", + "runtime": "python3.11", + "s3_bucket": null, + "s3_key": null, + "s3_object_version": null, + "signing_job_arn": "", + "signing_profile_version_arn": "", + "skip_destroy": false, + "snap_start": [], + "source_code_hash": "JhTe97YTSvuFlvDFGzhFP+f6yE7Rn6HSp2Y1SYVlOVY=", + "source_code_size": 12141, + "tags": null, + "tags_all": {}, + "timeout": 60, + "timeouts": null, + "tracing_config": [ + { + "mode": "PassThrough" + } + ], + "version": "$LATEST", + "vpc_config": [] + }, + "sensitive_attributes": [], + "identity_schema_version": 0, + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6NjAwMDAwMDAwMDAwLCJ1cGRhdGUiOjYwMDAwMDAwMDAwMH19", + "dependencies": [ + "aws_iam_role.iam_for_lambda", + "aws_lambda_layer_version.layer", + "data.archive_file.lambda", + "data.archive_file.layer", + "data.aws_iam_policy_document.assume_role", + "null_resource.pip_install" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_lambda_layer_version", + "name": "layer", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "arn": "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test:1", + "code_sha256": "dB5NITnNHiiWWQtFv9f3eYWRilrtiE60AJNMWRadSlA=", + "compatible_architectures": null, + "compatible_runtimes": [ + "python3.11" + ], + "created_date": "2026-05-27T17:09:07.743+0000", + "description": "", + "filename": "./layer.zip", + "id": "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test:1", + "layer_arn": "arn:aws:lambda:us-east-1:695105795926:layer:openai-layer-test", + "layer_name": "openai-layer-test", + "license_info": "", + "s3_bucket": null, + "s3_key": null, + "s3_object_version": null, + "signing_job_arn": "", + "signing_profile_version_arn": "", + "skip_destroy": false, + "source_code_hash": "dB5NITnNHiiWWQtFv9f3eYWRilrtiE60AJNMWRadSlA=", + "source_code_size": 7103838, + "version": "1" + }, + "sensitive_attributes": [], + "identity_schema_version": 0, + "private": "bnVsbA==", + "dependencies": [ + "data.archive_file.layer", + "null_resource.pip_install" + ] + } + ] + }, + { + "mode": "managed", + "type": "null_resource", + "name": "pip_install", + "provider": "provider[\"registry.terraform.io/hashicorp/null\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "5491774440303221650", + "triggers": { + "shell_hash": "84016380c6c240dd563a10e364ece2d65f4ad6c7313b2dd69cefbeb949fcfa4b" + } + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + } + ], + "check_results": null +} diff --git a/test.tfvars b/test.tfvars new file mode 100644 index 0000000..a8e80a8 --- /dev/null +++ b/test.tfvars @@ -0,0 +1 @@ +environment = "test" diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..1d106d3 --- /dev/null +++ b/variables.tf @@ -0,0 +1,15 @@ +variable "environment" { + description = "Deployment environment name" + type = string + default = "prod" +} + +variable "region" { + description = "AWS region" + type = string + default = "us-east-1" +} + +locals { + env = terraform.workspace == "default" ? "prod" : terraform.workspace +}