在 Swift SOTO 中使用 AWS Rekognition
Use AWS Rekognition in Swift SOTO
我用过devhr python lambda function as a model for my Swift Lambda function using Soto for AWS。当图像上传到 S3 时,Lambda 函数将由 S3 事件触发,并使用 AWS Rekognition 服务将标签(图像中对象的描述)添加到 DynamoDB 数据库。我在使 rekFunction 功能正确时遇到问题,我希望有人可以建议如何使其工作。
我目前所做的Swift代码:
import AWSLambdaRuntime
import AWSLambdaEvents
import NIO
import Foundation
import SotoS3
import SotoRekognition
import SotoDynamoDB
struct Bucket: Decodable {
let name: String
}
struct Object: Decodable {
let key: String
}
struct MyS3: Decodable {
let bucket: Bucket
let object: Object
}
struct Record: Decodable {
let s3: MyS3
}
struct Input: Decodable {
let records: [Record]
}
struct Output: Encodable {
let result: String
}
struct MyHandler: EventLoopLambdaHandler {
typealias In = APIGateway.V2.Request
typealias Out = APIGateway.V2.Response
let minConfidence: Float = 50
let awsClient: AWSClient
init(context: Lambda.InitializationContext) {
self.awsClient = AWSClient(httpClientProvider: .createNewWithEventLoopGroup(context.eventLoop))
}
func shutdown(context: Lambda.ShutdownContext) -> EventLoopFuture<Void> {
let promise = context.eventLoop.makePromise(of: Void.self)
awsClient.shutdown { error in
if let error = error {
promise.fail(error)
} else {
promise.succeed(())
}
}
return context.eventLoop.makeSucceededFuture(())
}
func handle(context: Lambda.Context, event: In) -> EventLoopFuture<Out> {
guard let input: Input = try? event.bodyObject() else {
return context.eventLoop.makeSucceededFuture(APIGateway.V2.Response(with: APIError.requestError, statusCode: .badRequest))
}
for record in input.records {
let ourBucket = record.s3.bucket.name
let ourKey = record.s3.object.key
// For each message (photo) get the bucket name and key
rekFunction(bucket: ourBucket, key: ourKey)
}
let output = Output(result: "Finished!")
let apigatewayOutput = APIGateway.V2.Response(with: output, statusCode: .ok)
return context.eventLoop.makeSucceededFuture(apigatewayOutput)
}
func rekFunction(bucket: String, key: String) {
let safeKey = key.replacingOccurrences(of: "%3A", with: ":")
print("Currently processing the following image")
print("Bucket:", bucket, " key name:", safeKey)
var objectsDetected: [String] = []
var imageLabels = [ "image": safeKey ]
let s3Client = S3(client: awsClient, region: .euwest1)
let s3Object = Rekognition.S3Object(bucket: bucket, name: safeKey)
let image = Rekognition.Image(s3Object: s3Object)
let rekognitionClient = Rekognition(client: awsClient)
let detectLabelsRequest = Rekognition.DetectLabelsRequest(image: image, maxLabels: 10, minConfidence: minConfidence)
rekognitionClient.detectLabels(detectLabelsRequest)
.flatMap { detectLabelsResponse -> EventLoopFuture<Void> in
if let labels = detectLabelsResponse.labels {
// Add all of our labels into imageLabels by iterating over response['Labels']
for label in labels {
if let name = label.name {
objectsDetected.append(name)
let itemAtt = "object\(objectsDetected.count)"
// We now have our shiny new item ready to put into DynamoDB
imageLabels[itemAtt] = name
// Instantiate a table resource object of our environment variable
let imageLabelsTable = // Environment("TABLE") How can I read env vars?
let table = SotoDynamoDB.getTable(imageLabelsTable) // python: table = dynamodb.Table(imageLabelsTable)
// python: table.put_item(Item=imageLabels)
}
}
}
return ???
}
}
}
Lambda.run { MyHandler(context: [=11=]) }
这里有很多问题要讨论。
- 因为您是从 S3 事件触发的。
MyLambda.In
类型别名应该是 S3.Event
并且没有任何等待结果 MyLambda.Out
应该是 Void
.
- 您可以使用
Lambda.env("TABLE")
提取环境变量。
- 至于写入 DynamoDB table 最好的方法可能是使用 Soto DynamoDB Codable 支持。在下面的示例中,我假设您使用 s3 存储桶和密钥的组合作为密钥。
struct RekEntry: Codable {
let key: String
let labels: [String]
}
let entry = RekEntry(
key: "\(bucket)/\(key)"
labels: labels
)
let putRequest = DynamoDB.PutItemCodableInput(
item: entry,
tableName: Lambda.env("TABLE")
)
return dynamoDB.putItem(putRequest)
- 最后 return 从你的 flatMap 中得到什么。首先,您的函数
rekFunction
需要 return 一个 EventLoopFuture<Void>
,因为这是您从 Lambda 处理程序 return 获取的内容。因此,您会将上一点中 dynamoDB.putItem
的结果映射到 Void.
func rekFunction(bucket: String, key: String) -> EventLoopFuture<Void> {
...
return rekognitionClient.detectLabels(detectLabelsRequest)
.flatMap {
...
return dynamoDB.putItem(putRequest)
}
.map { _ in }
}
我希望涵盖所有内容
我用过devhr python lambda function as a model for my Swift Lambda function using Soto for AWS。当图像上传到 S3 时,Lambda 函数将由 S3 事件触发,并使用 AWS Rekognition 服务将标签(图像中对象的描述)添加到 DynamoDB 数据库。我在使 rekFunction 功能正确时遇到问题,我希望有人可以建议如何使其工作。
我目前所做的Swift代码:
import AWSLambdaRuntime
import AWSLambdaEvents
import NIO
import Foundation
import SotoS3
import SotoRekognition
import SotoDynamoDB
struct Bucket: Decodable {
let name: String
}
struct Object: Decodable {
let key: String
}
struct MyS3: Decodable {
let bucket: Bucket
let object: Object
}
struct Record: Decodable {
let s3: MyS3
}
struct Input: Decodable {
let records: [Record]
}
struct Output: Encodable {
let result: String
}
struct MyHandler: EventLoopLambdaHandler {
typealias In = APIGateway.V2.Request
typealias Out = APIGateway.V2.Response
let minConfidence: Float = 50
let awsClient: AWSClient
init(context: Lambda.InitializationContext) {
self.awsClient = AWSClient(httpClientProvider: .createNewWithEventLoopGroup(context.eventLoop))
}
func shutdown(context: Lambda.ShutdownContext) -> EventLoopFuture<Void> {
let promise = context.eventLoop.makePromise(of: Void.self)
awsClient.shutdown { error in
if let error = error {
promise.fail(error)
} else {
promise.succeed(())
}
}
return context.eventLoop.makeSucceededFuture(())
}
func handle(context: Lambda.Context, event: In) -> EventLoopFuture<Out> {
guard let input: Input = try? event.bodyObject() else {
return context.eventLoop.makeSucceededFuture(APIGateway.V2.Response(with: APIError.requestError, statusCode: .badRequest))
}
for record in input.records {
let ourBucket = record.s3.bucket.name
let ourKey = record.s3.object.key
// For each message (photo) get the bucket name and key
rekFunction(bucket: ourBucket, key: ourKey)
}
let output = Output(result: "Finished!")
let apigatewayOutput = APIGateway.V2.Response(with: output, statusCode: .ok)
return context.eventLoop.makeSucceededFuture(apigatewayOutput)
}
func rekFunction(bucket: String, key: String) {
let safeKey = key.replacingOccurrences(of: "%3A", with: ":")
print("Currently processing the following image")
print("Bucket:", bucket, " key name:", safeKey)
var objectsDetected: [String] = []
var imageLabels = [ "image": safeKey ]
let s3Client = S3(client: awsClient, region: .euwest1)
let s3Object = Rekognition.S3Object(bucket: bucket, name: safeKey)
let image = Rekognition.Image(s3Object: s3Object)
let rekognitionClient = Rekognition(client: awsClient)
let detectLabelsRequest = Rekognition.DetectLabelsRequest(image: image, maxLabels: 10, minConfidence: minConfidence)
rekognitionClient.detectLabels(detectLabelsRequest)
.flatMap { detectLabelsResponse -> EventLoopFuture<Void> in
if let labels = detectLabelsResponse.labels {
// Add all of our labels into imageLabels by iterating over response['Labels']
for label in labels {
if let name = label.name {
objectsDetected.append(name)
let itemAtt = "object\(objectsDetected.count)"
// We now have our shiny new item ready to put into DynamoDB
imageLabels[itemAtt] = name
// Instantiate a table resource object of our environment variable
let imageLabelsTable = // Environment("TABLE") How can I read env vars?
let table = SotoDynamoDB.getTable(imageLabelsTable) // python: table = dynamodb.Table(imageLabelsTable)
// python: table.put_item(Item=imageLabels)
}
}
}
return ???
}
}
}
Lambda.run { MyHandler(context: [=11=]) }
这里有很多问题要讨论。
- 因为您是从 S3 事件触发的。
MyLambda.In
类型别名应该是S3.Event
并且没有任何等待结果MyLambda.Out
应该是Void
. - 您可以使用
Lambda.env("TABLE")
提取环境变量。 - 至于写入 DynamoDB table 最好的方法可能是使用 Soto DynamoDB Codable 支持。在下面的示例中,我假设您使用 s3 存储桶和密钥的组合作为密钥。
struct RekEntry: Codable {
let key: String
let labels: [String]
}
let entry = RekEntry(
key: "\(bucket)/\(key)"
labels: labels
)
let putRequest = DynamoDB.PutItemCodableInput(
item: entry,
tableName: Lambda.env("TABLE")
)
return dynamoDB.putItem(putRequest)
- 最后 return 从你的 flatMap 中得到什么。首先,您的函数
rekFunction
需要 return 一个EventLoopFuture<Void>
,因为这是您从 Lambda 处理程序 return 获取的内容。因此,您会将上一点中dynamoDB.putItem
的结果映射到 Void.
func rekFunction(bucket: String, key: String) -> EventLoopFuture<Void> {
...
return rekognitionClient.detectLabels(detectLabelsRequest)
.flatMap {
...
return dynamoDB.putItem(putRequest)
}
.map { _ in }
}
我希望涵盖所有内容