

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 Lambda 無伺服器處理檔案
<a name="tutorial-process-files-with-lambda"></a>

檔案處理工作流程通常從到達 NFS 或 SMB 檔案共享的檔案開始：從分支辦公室掃描的文件、現場團隊上傳的影像、從聯絡中心擷取的音訊，或合作夥伴交付的資料檔案。

當 Amazon S3 存取點連接至 FSx for ONTAP 磁碟區時， AWS Lambda 函數會直接使用 Amazon S3 API 讀取和寫入檔案。檔案層級操作可以無伺服器方式針對使用者和應用程式透過 NFS 和 SMB 存取的相同資料進行處理。

本教學課程顯示三種常見的檔案處理模式。每個範例會透過存取點從磁碟區讀取檔案、使用 AWS 服務或程式庫處理檔案，並將結果寫入磁碟區。


| 範例 | Input | 處理 | Output | 
| --- | --- | --- | --- | 
| [範例 1：產生影像縮圖](#tutorial-lambda-thumbnail) | JPEG 影像 | Pillow （影像庫） | 調整大小縮圖 | 
| [範例 2：從文件擷取文字](#tutorial-lambda-textract) | PDF 文件 | Amazon Textract | 擷取的文字 (JSON) | 
| [範例 3：轉錄音訊檔案](#tutorial-lambda-transcribe) | MP3 音訊 | Amazon Transcribe | 文字記錄 (JSON) | 

**注意**  
本教學課程大約需要 **40 到 60 分鐘**才能完成。 AWS 服務 使用的 會針對您建立的資源產生費用。如果您立即完成所有步驟，包括**清除**區段，則美國東部 （維吉尼亞北部） 的預期成本低於 **1 美元**。 AWS 區域此預估不包含 FSx for ONTAP 磁碟區本身的持續費用。

## 先決條件
<a name="tutorial-lambda-prerequisites"></a>

開始前，請確定您具有下列項目：
+ 已連接 Amazon S3 存取點的 ONTAP 磁碟區的 FSx。如需建立存取點的說明，請參閱 [建立存取點](fsxn-creating-access-points.md)。
+ 存取點的存取點別名。您可以在 Amazon FSx 主控台或執行 找到此項目`aws fsx describe-s3-access-point-attachments`。
+ AWS CLI 已安裝並設定 第 1 版或第 2 版。本教學課程中的`aws lambda invoke`命令包含 `--cli-binary-format raw-in-base64-out`選項，這是第 2 AWS CLI 版中的必要項目，因此原始 JSON 承載不會解譯為 base64。如果您使用 AWS CLI 版本 1，請省略該選項。
+ 發起人 （執行本教學課程的使用者或角色） 叫用 Lambda 函數 (`lambda:CreateFunction`、`lambda:InvokeFunction`)、存取 Amazon S3 存取點 (`s3:GetObject`、`s3:PutObject`) 和傳遞 Lambda 執行角色 () 的 IAM 許可`iam:PassRole`。

**注意**  
本教學課程使用預設 Lambda 組態，其中 函數會在 VPC 外部的受管網路中執行。在這種情況下，存取點必須具有**網際網路**原始伺服器，函數才能連接它。如果您將 Lambda 函數連接至 VPC，您可以改為在存取點上使用 VPC 網路原始伺服器；VPC 必須具有 Amazon S3 Gateway 或 Interface 端點。如需詳細資訊，請參閱[設定 Amazon S3 存取點的網路存取](configuring-network-access-for-s3-access-points.md)。

## 步驟 1：上傳範例檔案
<a name="tutorial-lambda-upload-samples"></a>

下載下列範例檔案，並透過存取點將其上傳至 FSx for ONTAP 磁碟區。在本教學課程中`{{my-ap-alias-ext-s3alias}}`將 取代為您的存取點別名。
+ **範例映像：**下載 [NASA 藍色 Marble 映像](https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73909/world.topo.bathy.200412.3x5400x2700.jpg) （公有網域，2.4 MB)，並將其儲存為 。 `sample-image.jpg`
+ **範例音訊：**從 [Amazon Transcribe 入門教學](https://docs.aws.amazon.com/hands-on/latest/create-audio-transcript-transcribe/create-audio-transcript-transcribe.html)課程 (410 KB) 下載[範例音訊檔案](https://d1.awsstatic.com/tmt/create-audio-transcript-transcribe/transcribe-sample.5fc2109bb28268d10fbc677e64b7e59256783d3c.mp3)，並將其儲存為 `sample-audio.mp3`。

透過存取點將範例檔案上傳至 FSx for ONTAP 磁碟區。

```
$ aws s3 cp sample-image.jpg s3://{{my-ap-alias-ext-s3alias}}/samples/images/sample-image.jpg
aws s3 cp sample-audio.mp3 s3://{{my-ap-alias-ext-s3alias}}/samples/audio/sample-audio.mp3
```

**注意**  
範例影像是 NASA 藍色 Marble 相片 （公有網域，2.4 MB)。範例音訊來自 [Amazon Transcribe 入門教學](https://docs.aws.amazon.com/hands-on/latest/create-audio-transcript-transcribe/create-audio-transcript-transcribe.html)課程 (410 KB)。範例 PDF 會在 中產生[範例 2：從文件擷取文字](#tutorial-lambda-textract)。

## 步驟 2：建立 Lambda 執行角色
<a name="tutorial-lambda-create-role"></a>

Lambda 函數會擔任執行角色來與其他 互動 AWS 服務。在本教學課程中，連接 CloudWatch Logs 日誌記錄的 AWS受管`AWSLambdaBasicExecutionRole`政策，然後新增內嵌政策，將存取權授予 Amazon S3 存取點，以及範例使用的 Textract 和 Transcribe APIs。

### 建立 Lambda 執行角色
<a name="tutorial-lambda-create-role-steps"></a>

將 `{{region}}`、 `{{account-id}}`和 取代`{{access-point-name}}`為您的值。

1. 將下列信任政策儲存為 `trust-policy.json`。

   ```
   {
       "Version": "2012-10-17", 		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {"Service": "lambda.amazonaws.com"},
               "Action": "sts:AssumeRole"
           }
       ]
   }
   ```

1. 將下列內嵌許可政策儲存為 `permissions-policy.json`。它會將存取權授予存取點，以及範例使用的其他服務。

   ```
   {
       "Version": "2012-10-17", 		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
               "Resource": [
                   "arn:aws:s3:{{region}}:{{account-id}}:accesspoint/{{access-point-name}}",
                   "arn:aws:s3:{{region}}:{{account-id}}:accesspoint/{{access-point-name}}/object/*"
               ]
           },
           {
               "Effect": "Allow",
               "Action": ["textract:DetectDocumentText"],
               "Resource": "*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "transcribe:StartTranscriptionJob",
                   "transcribe:GetTranscriptionJob"
               ],
               "Resource": "*"
           }
       ]
   }
   ```

1. 建立角色、連接受管記錄政策，以及連接內嵌政策。

   ```
   $ aws iam create-role \
       --role-name {{fsxn-lambda-file-processor}} \
       --assume-role-policy-document file://trust-policy.json
   
   aws iam attach-role-policy \
       --role-name {{fsxn-lambda-file-processor}} \
       --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
   
   aws iam put-role-policy \
       --role-name {{fsxn-lambda-file-processor}} \
       --policy-name fsxn-access-point-policy \
       --policy-document file://permissions-policy.json
   ```

## 整合到您的工作流程
<a name="tutorial-lambda-workflow-integration"></a>

本教學課程中的範例使用手動調用與測試事件。在生產環境中，您可以使用下列方法自動觸發這些函數：
+ **Amazon EventBridge 排程。**依週期性排程執行函數 （例如，每小時或每天） 來處理新檔案。函數可以透過存取點列出檔案，並處理任何尚未處理的檔案。如需詳細資訊，請參閱《Amazon [ EventBridge 使用者指南》中的使用 EventBridge 排程 Lambda 函數](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-run-lambda-schedule.html)。 * EventBridge *
+ **Amazon API Gateway。**將函數公開為 HTTP API，以便使用者或應用程式可以隨需請求處理特定檔案。如需詳細資訊，請參閱《*Amazon API Gateway * [API Gateway 開發人員指南》中的使用 Lambda 整合建置 API Gateway REST](https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-lambda-integration.html) API。
+ **Step Functions。**協調結合多個 Lambda 函數的多步驟檔案處理管道。例如，從文件中擷取文字、翻譯文字，然後將結果寫回磁碟區的工作流程。如需詳細資訊，請參閱《 *AWS Step Functions 開發人員指南*》中的[使用 Step Functions 呼叫 Lambda](https://docs.aws.amazon.com/step-functions/latest/dg/connect-lambda.html)。

## 範例 1：產生影像縮圖
<a name="tutorial-lambda-thumbnail"></a>

此範例會從 FSx for ONTAP 磁碟區讀取 JPEG 影像，使用 Pillow 影像程式庫將其調整為 200 像素的縮圖大小，並將縮圖寫回磁碟區。

**Lambda 函式程式碼**

將下列程式碼儲存為 `lambda_function.py`。

```
import boto3
from io import BytesIO
from PIL import Image

s3 = boto3.client('s3')

def lambda_handler(event, context):
    bucket = event['access_point_alias']
    key = event['key']

    # Read the image from FSx through the access point
    response = s3.get_object(Bucket=bucket, Key=key)
    image_data = response['Body'].read()

    # Resize to thumbnail
    img = Image.open(BytesIO(image_data))
    img.thumbnail((200, 200))

    # Write the thumbnail back to FSx
    buffer = BytesIO()
    img.save(buffer, format='JPEG', quality=85)
    buffer.seek(0)

    thumbnail_key = key.rsplit('.', 1)[0] + '_thumbnail.jpg'
    s3.put_object(
        Bucket=bucket,
        Key=thumbnail_key,
        Body=buffer.getvalue(),
        ContentType='image/jpeg'
    )

    return {
        'original_size': len(image_data),
        'thumbnail_size': len(buffer.getvalue()),
        'thumbnail_key': thumbnail_key
    }
```

**建立和叫用 函數**

此函數需要 Pillow 程式庫。建立部署套件，其中包含為 Lambda Linux 執行時間建置的 Pillow。

```
$ # Create a deployment package with Pillow for Lambda (Linux)
mkdir package && pip install Pillow -t package/ \
    --platform manylinux2014_x86_64 --only-binary=:all:
cd package && zip -r ../thumbnail-function.zip .
cd .. && zip thumbnail-function.zip lambda_function.py

# Create the function
aws lambda create-function \
    --function-name {{fsxn-thumbnail-generator}} \
    --runtime python3.12 \
    --handler lambda_function.lambda_handler \
    --role arn:aws:iam::{{account-id}}:role/{{fsxn-lambda-file-processor}} \
    --zip-file fileb://thumbnail-function.zip \
    --timeout 30 \
    --memory-size 256

# Invoke with a test event
aws lambda invoke \
    --function-name {{fsxn-thumbnail-generator}} \
    --cli-binary-format raw-in-base64-out \
    --payload '{"access_point_alias": "{{my-ap-alias-ext-s3alias}}", "key": "samples/images/sample-image.jpg"}' \
    response.json

cat response.json
```

**驗證結果**

```
$ aws s3 ls s3://{{my-ap-alias-ext-s3alias}}/samples/images/
2024-01-23 12:19:32    2566770 sample-image.jpg
2024-01-23 12:25:49       7065 sample-image_thumbnail.jpg
```

原始 2.4 MB 影像 (5400 × 2700 像素） 已調整為 7 KB 縮圖 (200 × 100 像素）。

## 範例 2：從文件擷取文字
<a name="tutorial-lambda-textract"></a>

此範例會從 FSx for ONTAP 磁碟區讀取 PDF 文件，將其傳送至 Amazon Textract 以擷取文字，並將擷取的文字作為 JSON 檔案寫入磁碟區。

**建立和上傳範例 PDF**

在此範例中，您需要 FSx for ONTAP 磁碟區的 PDF 文件。下列 Python 指令碼會產生簡單的發票 PDF，並透過存取點上傳。在本機電腦上執行此指令碼 （不在 Lambda 中）。

```
$ pip install fpdf2 boto3
```

```
# create_invoice.py — run locally to generate and upload a sample PDF
from fpdf import FPDF
import boto3

pdf = FPDF()
pdf.add_page()
pdf.set_font("Helvetica", "B", 24)
pdf.cell(0, 15, "INVOICE", new_x="LMARGIN", new_y="NEXT", align="C")
pdf.set_font("Helvetica", "", 12)
pdf.cell(0, 8, "Invoice Number: INV-2024-00142", new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 8, "Date: January 15, 2024", new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 8, "Customer: Example Corp", new_x="LMARGIN", new_y="NEXT")
pdf.ln(5)
pdf.set_font("Helvetica", "B", 12)
pdf.cell(80, 8, "Description", border=1)
pdf.cell(30, 8, "Qty", border=1, align="C")
pdf.cell(40, 8, "Unit Price", border=1, align="R")
pdf.cell(40, 8, "Amount", border=1, align="R")
pdf.ln()
pdf.set_font("Helvetica", "", 12)
for desc, qty, price, amt in [
    ("Cloud Storage Service", "1", "$2,400.00", "$2,400.00"),
    ("Data Transfer (TB)", "5", "$90.00", "$450.00"),
    ("Technical Support", "1", "$500.00", "$500.00"),
]:
    pdf.cell(80, 8, desc, border=1)
    pdf.cell(30, 8, qty, border=1, align="C")
    pdf.cell(40, 8, price, border=1, align="R")
    pdf.cell(40, 8, amt, border=1, align="R")
    pdf.ln()

s3 = boto3.client('s3')
s3.put_object(
    Bucket='{{my-ap-alias-ext-s3alias}}',
    Key='samples/documents/invoice.pdf',
    Body=pdf.output(),
    ContentType='application/pdf'
)
print("Uploaded invoice.pdf")
```

```
$ python3 create_invoice.py
```

**Lambda 函式程式碼**

將下列程式碼儲存為 `lambda_function.py`。

```
import boto3
import json

s3 = boto3.client('s3')
textract = boto3.client('textract')

def lambda_handler(event, context):
    bucket = event['access_point_alias']
    key = event['key']

    # Read the PDF from FSx through the access point
    response = s3.get_object(Bucket=bucket, Key=key)
    document_bytes = response['Body'].read()

    # Extract text with Textract
    textract_response = textract.detect_document_text(
        Document={'Bytes': document_bytes}
    )

    lines = [
        block['Text']
        for block in textract_response['Blocks']
        if block['BlockType'] == 'LINE'
    ]

    # Write extracted text as JSON back to FSx
    result = {
        'source_file': key,
        'total_lines': len(lines),
        'extracted_text': lines
    }

    output_key = key.rsplit('.', 1)[0] + '_extracted.json'
    s3.put_object(
        Bucket=bucket,
        Key=output_key,
        Body=json.dumps(result, indent=2),
        ContentType='application/json'
    )

    return {
        'lines_extracted': len(lines),
        'output_key': output_key
    }
```

**建立和叫用 函數**

```
$ zip textract-function.zip lambda_function.py

aws lambda create-function \
    --function-name {{fsxn-text-extractor}} \
    --runtime python3.12 \
    --handler lambda_function.lambda_handler \
    --role arn:aws:iam::{{account-id}}:role/{{fsxn-lambda-file-processor}} \
    --zip-file fileb://textract-function.zip \
    --timeout 30 \
    --memory-size 256

aws lambda invoke \
    --function-name {{fsxn-text-extractor}} \
    --cli-binary-format raw-in-base64-out \
    --payload '{"access_point_alias": "{{my-ap-alias-ext-s3alias}}", "key": "samples/documents/invoice.pdf"}' \
    response.json

cat response.json
```

輸出範例：

```
{"lines_extracted": 22, "output_key": "samples/documents/invoice_extracted.json"}
```

## 範例 3：轉錄音訊檔案
<a name="tutorial-lambda-transcribe"></a>

此範例會針對儲存在 FSx for ONTAP 磁碟區的音訊檔案啟動 Amazon Transcribe 任務。Amazon Transcribe 會使用媒體檔案 URI 中的存取點別名，直接從存取點讀取音訊檔案。當任務完成時， 函數會將文字記錄寫回磁碟區。

**Lambda 函式程式碼**

將下列程式碼儲存為 `lambda_function.py`。

```
import boto3
import json
import time
import urllib.request

s3 = boto3.client('s3')
transcribe = boto3.client('transcribe')

def lambda_handler(event, context):
    bucket = event['access_point_alias']
    key = event['key']
    media_format = key.rsplit('.', 1)[-1]  # mp3, wav, etc.

    # Start a Transcribe job pointing to the file on FSx
    job_name = f"fsxn-{int(time.time())}"
    transcribe.start_transcription_job(
        TranscriptionJobName=job_name,
        Media={'MediaFileUri': f's3://{bucket}/{key}'},
        MediaFormat=media_format,
        LanguageCode='en-US'
    )

    # Wait for the job to complete
    while True:
        status = transcribe.get_transcription_job(
            TranscriptionJobName=job_name
        )
        state = status['TranscriptionJob']['TranscriptionJobStatus']
        if state in ('COMPLETED', 'FAILED'):
            break
        time.sleep(5)

    if state == 'FAILED':
        raise Exception(
            status['TranscriptionJob'].get('FailureReason', 'Unknown error')
        )

    # Download the transcript
    transcript_uri = status['TranscriptionJob']['Transcript']['TranscriptFileUri']
    with urllib.request.urlopen(transcript_uri) as resp:
        transcript_data = json.loads(resp.read())

    transcript_text = transcript_data['results']['transcripts'][0]['transcript']

    # Write the transcript back to FSx
    result = {
        'source_file': key,
        'job_name': job_name,
        'transcript': transcript_text
    }

    output_key = key.rsplit('.', 1)[0] + '_transcript.json'
    s3.put_object(
        Bucket=bucket,
        Key=output_key,
        Body=json.dumps(result, indent=2),
        ContentType='application/json'
    )

    return {
        'transcript_length': len(transcript_text),
        'output_key': output_key
    }
```

**建立和叫用 函數**

```
$ zip transcribe-function.zip lambda_function.py

aws lambda create-function \
    --function-name {{fsxn-audio-transcriber}} \
    --runtime python3.12 \
    --handler lambda_function.lambda_handler \
    --role arn:aws:iam::{{account-id}}:role/{{fsxn-lambda-file-processor}} \
    --zip-file fileb://transcribe-function.zip \
    --timeout 120

aws lambda invoke \
    --function-name {{fsxn-audio-transcriber}} \
    --cli-binary-format raw-in-base64-out \
    --payload '{"access_point_alias": "{{my-ap-alias-ext-s3alias}}", "key": "samples/audio/sample-audio.mp3"}' \
    --cli-read-timeout 180 \
    response.json

cat response.json
```

**注意**  
Transcribe 任務通常需要 15 到 45 秒才能完成。函數的逾時設定為 120 秒以允許此操作。

## 考量事項
<a name="tutorial-lambda-considerations"></a>
+ **預設組態所需的網際網路原始伺服器。**根據預設，Lambda 會從 VPC 外部的受管基礎設施存取 Amazon S3，這需要網際網路來源存取點。如果您將 Lambda 函數連接至 VPC，則可以改用 VPC 來源存取點。如需詳細資訊，請參閱先決條件。
+ **檔案大小限制。**Lambda 函數的記憶體上限為 10 GB，執行時間上限為 15 分鐘。對於大型檔案，請考慮使用範圍讀取 (`GetObject` 搭配 `Range` 標頭） 或串流回應。
+ **Textract 限制。**同步 `DetectDocumentText` API 接受最多 10 MB 和 1 頁的文件。對於多頁文件，請使用非同步 `StartDocumentTextDetection` API。
+ **轉錄直接從存取點讀取。**Amazon Transcribe 接受 `MediaFileUri` 參數 () 中的存取點別名`s3://{{ap-alias}}/{{key}}`。Lambda 函數不需要下載和重新上傳音訊檔案。
+ **檔案系統使用者許可。**與存取點相關聯的檔案系統使用者必須具有輸入檔案的讀取許可，以及輸出目錄的寫入許可。

## 清除
<a name="tutorial-lambda-clean-up"></a>

若要避免持續收費，請刪除您在本教學課程中建立的資源。

```
$ # Delete Lambda functions
aws lambda delete-function --function-name {{fsxn-thumbnail-generator}}
aws lambda delete-function --function-name {{fsxn-text-extractor}}
aws lambda delete-function --function-name {{fsxn-audio-transcriber}}

# Delete the IAM role and policies
aws iam delete-role-policy \
    --role-name {{fsxn-lambda-file-processor}} \
    --policy-name fsxn-access-point-policy
aws iam detach-role-policy \
    --role-name {{fsxn-lambda-file-processor}} \
    --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam delete-role --role-name {{fsxn-lambda-file-processor}}

# Delete sample files from your FSx volume
aws s3 rm s3://{{my-ap-alias-ext-s3alias}}/samples/ --recursive
```