using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.S3Events;
using Amazon.Rekognition;
using Amazon.Rekognition.Model;
using Amazon.S3;
using Amazon.S3.Model;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace BlueprintBaseName._1
{
public class Function
{
///
/// The default minimum confidence used for detecting labels.
///
public const float DEFAULT_MIN_CONFIDENCE = 70f;
///
/// The name of the environment variable to set which will override the default minimum confidence level.
///
public const string MIN_CONFIDENCE_ENVIRONMENT_VARIABLE_NAME = "MinConfidence";
IAmazonS3 S3Client { get; }
IAmazonRekognition RekognitionClient { get; }
float MinConfidence { get; set; } = DEFAULT_MIN_CONFIDENCE;
HashSet SupportedImageTypes { get; } = new HashSet { ".png", ".jpg", ".jpeg" };
///
/// Default constructor used by AWS Lambda to construct the function. Credentials and Region information will
/// be set by the running Lambda environment.
///
/// This constuctor will also search for the environment variable overriding the default minimum confidence level
/// for label detection.
///
public Function()
{
this.S3Client = new AmazonS3Client();
this.RekognitionClient = new AmazonRekognitionClient();
var environmentMinConfidence = System.Environment.GetEnvironmentVariable(MIN_CONFIDENCE_ENVIRONMENT_VARIABLE_NAME);
if(!string.IsNullOrWhiteSpace(environmentMinConfidence))
{
float value;
if(float.TryParse(environmentMinConfidence, out value))
{
this.MinConfidence = value;
Console.WriteLine($"Setting minimum confidence to {this.MinConfidence}");
}
else
{
Console.WriteLine($"Failed to parse value {environmentMinConfidence} for minimum confidence. Reverting back to default of {this.MinConfidence}");
}
}
else
{
Console.WriteLine($"Using default minimum confidence of {this.MinConfidence}");
}
}
///
/// Constructor used for testing which will pass in the already configured service clients.
///
///
///
///
public Function(IAmazonS3 s3Client, IAmazonRekognition rekognitionClient, float minConfidence)
{
this.S3Client = s3Client;
this.RekognitionClient = rekognitionClient;
this.MinConfidence = minConfidence;
}
///
/// A function for responding to S3 create events. It will determine if the object is an image and use Amazon Rekognition
/// to detect labels and add the labels as tags on the S3 object.
///
///
///
///
public async Task FunctionHandler(S3Event input, ILambdaContext context)
{
foreach(var record in input.Records)
{
if(!SupportedImageTypes.Contains(Path.GetExtension(record.S3.Object.Key)))
{
Console.WriteLine($"Object {record.S3.Bucket.Name}:{record.S3.Object.Key} is not a supported image type");
continue;
}
Console.WriteLine($"Looking for labels in image {record.S3.Bucket.Name}:{record.S3.Object.Key}");
var detectResponses = await this.RekognitionClient.DetectLabelsAsync(new DetectLabelsRequest
{
MinConfidence = MinConfidence,
Image = new Image
{
S3Object = new Amazon.Rekognition.Model.S3Object
{
Bucket = record.S3.Bucket.Name,
Name = record.S3.Object.Key
}
}
});
var tags = new List();
foreach(var label in detectResponses.Labels)
{
if(tags.Count < 10)
{
Console.WriteLine($"\tFound Label {label.Name} with confidence {label.Confidence}");
tags.Add(new Tag { Key = label.Name, Value = label.Confidence.ToString() });
}
else
{
Console.WriteLine($"\tSkipped label {label.Name} with confidence {label.Confidence} because the maximum number of tags has been reached");
}
}
await this.S3Client.PutObjectTaggingAsync(new PutObjectTaggingRequest
{
BucketName = record.S3.Bucket.Name,
Key = record.S3.Object.Key,
Tagging = new Tagging
{
TagSet = tags
}
});
}
return;
}
}
}