Esempio n. 1
0
 private BMEssence CreateBmEssence(BMContent bmContent, S3Locator location, JToken mediaInfo)
 {
     return(new BMEssence
     {
         BmContent = bmContent.Id,
         Locations = new Locator[] { location },
         ["technicalMetadata"] = mediaInfo
     });
 }
Esempio n. 2
0
        public static async Task ProcessRekognitionResultAsync(AwsAiServiceWorkerRequest @event)
        {
            var resourceManager = @event.GetAwsV4ResourceManager();
            var table           = new DynamoDbTable(@event.StageVariables["TableName"]);
            var jobAssignmentId = @event.JobAssignmentId;

            var job = await RetrieveJobAsync(resourceManager, table, jobAssignmentId);

            try
            {
                var jobInput = job.JobInput;

                S3Locator outputLocation;
                if (!jobInput.TryGet <S3Locator>(nameof(outputLocation), out outputLocation))
                {
                    throw new Exception("Invalid or missing output location.");
                }

                var s3Bucket = outputLocation.AwsS3Bucket;

                var rekoJobId   = @event.JobExternalInfo.RekoJobId;
                var rekoJobType = @event.JobExternalInfo.RekoJobType;
                var status      = @event.JobExternalInfo.Status;

                if (status != "SUCCEEDED")
                {
                    throw new Exception($"AI Rekognition failed job info: rekognition status:" + status);
                }

                object data = null;
                switch (rekoJobType)
                {
                case "StartCelebrityRecognition":
                    var getCelebRecognitionParams = new GetCelebrityRecognitionRequest
                    {
                        JobId      = rekoJobId, /* required */
                        MaxResults = 1000000,
                        SortBy     = "TIMESTAMP"
                    };

                    var rekognitionClient = new AmazonRekognitionClient();
                    data = await rekognitionClient.GetCelebrityRecognitionAsync(getCelebRecognitionParams);

                    break;

                case "StartLabelDetection":
                    throw new NotImplementedException("StartLabelDetection has not yet been implemented");

                case "StartContentModeration":
                    throw new NotImplementedException("StartContentModeration has not yet been implemented");

                case "StartPersonTracking":
                    throw new NotImplementedException("StartPersonTracking has not yet been implemented");

                case "StartFaceDetection":
                    throw new NotImplementedException("StartLabelDetection has not yet been implemented");

                case "StartFaceSearch":
                    throw new NotImplementedException("StartLabelDetection has not yet been implemented");

                default:
                    throw new Exception($"Unknown job type '{rekoJobType}'");
                }

                if (data == null)
                {
                    throw new Exception($"No data was returned by AWS Rekognition");
                }

                var newS3Key = $"reko_{Guid.NewGuid()}.json";
                var s3Params = new PutObjectRequest
                {
                    BucketName  = outputLocation.AwsS3Bucket,
                    Key         = newS3Key,
                    ContentBody = data.ToMcmaJson().ToString(),
                    ContentType = "application/json"
                };

                try
                {
                    var destS3 = await outputLocation.GetClientAsync();

                    await destS3.PutObjectAsync(s3Params);
                }
                catch (Exception error)
                {
                    Logger.Error("Unable to write output file to bucket '" + s3Bucket + "' with key '" + newS3Key + "'");
                    Logger.Exception(error);
                }

                var jobOutput = new JobParameterBag();
                jobOutput["outputFile"] = new S3Locator
                {
                    AwsS3Bucket = s3Bucket,
                    AwsS3Key    = newS3Key
                };

                await UpdateJobAssignmentWithOutputAsync(table, jobAssignmentId, jobOutput);
                await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "COMPLETED");
            }
            catch (Exception error)
            {
                Logger.Exception(error);

                try
                {
                    await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "FAILED", error.ToString());
                }
                catch (Exception innerError)
                {
                    Logger.Exception(innerError);
                }
            }
        }
Esempio n. 3
0
        internal static async Task ProcessJobAssignmentAsync(AwsAiServiceWorkerRequest @event)
        {
            var resourceManager = @event.GetAwsV4ResourceManager();
            var table           = new DynamoDbTable(@event.StageVariables["TableName"]);
            var jobAssignmentId = @event.JobAssignmentId;

            try
            {
                // 1. Setting job assignment status to RUNNING
                await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "RUNNING", null);

                // 2. Retrieving WorkflowJob
                var job = await RetrieveJobAsync(resourceManager, table, jobAssignmentId);

                // 3. Retrieve JobProfile
                var jobProfile = await RetrieveJobProfileAsync(resourceManager, job);

                // 4. Retrieve job inputParameters
                var jobInput = job.JobInput;

                // 5. Check if we support jobProfile and if we have required parameters in jobInput
                ValidateJobProfile(jobProfile, jobInput);

                S3Locator inputFile;
                if (!jobInput.TryGet <S3Locator>(nameof(inputFile), out inputFile))
                {
                    throw new Exception("Invalid or missing input file.");
                }

                S3Locator outputLocation;
                if (!jobInput.TryGet <S3Locator>(nameof(outputLocation), out outputLocation))
                {
                    throw new Exception("Invalid or missing output location.");
                }

                switch (jobProfile.Name)
                {
                case JOB_PROFILE_TRANSCRIBE_AUDIO:
                    string mediaFileUrl;
                    if (!string.IsNullOrWhiteSpace(inputFile.HttpEndpoint))
                    {
                        mediaFileUrl = inputFile.HttpEndpoint;
                    }
                    else
                    {
                        var bucketLocation = await inputFile.GetBucketLocationAsync();

                        var s3SubDomain = !string.IsNullOrWhiteSpace(bucketLocation) ? $"s3-{bucketLocation}" : "s3";
                        mediaFileUrl = $"https://{s3SubDomain}.amazonaws.com/{inputFile.AwsS3Bucket}/{inputFile.AwsS3Key}";
                    }

                    string mediaFormat;
                    if (mediaFileUrl.EndsWith("mp3", StringComparison.OrdinalIgnoreCase))
                    {
                        mediaFormat = "mp3";
                    }
                    else if (mediaFileUrl.EndsWith("mp4", StringComparison.OrdinalIgnoreCase))
                    {
                        mediaFormat = "mp4";
                    }
                    else if (mediaFileUrl.EndsWith("wav", StringComparison.OrdinalIgnoreCase))
                    {
                        mediaFormat = "wav";
                    }
                    else if (mediaFileUrl.EndsWith("flac", StringComparison.OrdinalIgnoreCase))
                    {
                        mediaFormat = "flac";
                    }
                    else
                    {
                        throw new Exception($"Unable to determine media format from input file '{mediaFileUrl}'");
                    }

                    var transcribeParameters = new StartTranscriptionJobRequest
                    {
                        TranscriptionJobName = "TranscriptionJob-" + jobAssignmentId.Substring(jobAssignmentId.LastIndexOf("/") + 1),
                        LanguageCode         = "en-US",
                        Media = new Media {
                            MediaFileUri = mediaFileUrl
                        },
                        MediaFormat      = mediaFormat,
                        OutputBucketName = @event.StageVariables["ServiceOutputBucket"]
                    };

                    var transcribeService = new AmazonTranscribeServiceClient();

                    var startJobResponse = await transcribeService.StartTranscriptionJobAsync(transcribeParameters);

                    Logger.Debug(startJobResponse.ToMcmaJson().ToString());
                    break;

                case JOB_PROFILE_TRANSLATE_TEXT:
                    var s3Bucket = inputFile.AwsS3Bucket;
                    var s3Key    = inputFile.AwsS3Key;

                    GetObjectResponse s3Object;
                    try
                    {
                        s3Object = await inputFile.GetAsync();
                    }
                    catch (Exception error)
                    {
                        throw new Exception($"Unable to read file in bucket '{s3Bucket}' with key '{s3Key}'.", error);
                    }

                    var inputText = await new StreamReader(s3Object.ResponseStream).ReadToEndAsync();

                    var translateParameters = new TranslateTextRequest
                    {
                        SourceLanguageCode = jobInput.TryGet("sourceLanguageCode", out string srcLanguageCode) ? srcLanguageCode : "auto",
                        TargetLanguageCode = jobInput.Get <string>("targetLanguageCode"),
                        Text = inputText
                    };

                    var translateService  = new AmazonTranslateClient();
                    var translateResponse = await translateService.TranslateTextAsync(translateParameters);

                    var s3Params = new PutObjectRequest
                    {
                        BucketName  = outputLocation.AwsS3Bucket,
                        Key         = (!string.IsNullOrWhiteSpace(outputLocation.AwsS3KeyPrefix) ? outputLocation.AwsS3Key : string.Empty) + Guid.NewGuid() + ".txt",
                        ContentBody = translateResponse.TranslatedText
                    };

                    var outputS3 = await outputLocation.GetClientAsync();

                    await outputS3.PutObjectAsync(s3Params);

                    var jobOutput = new JobParameterBag();
                    jobOutput["outputFile"] = new S3Locator
                    {
                        AwsS3Bucket = s3Params.BucketName,
                        AwsS3Key    = s3Params.Key
                    };

                    Logger.Debug("Updating job assignment");
                    await UpdateJobAssignmentWithOutputAsync(table, jobAssignmentId, jobOutput);
                    await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "COMPLETED");

                    break;

                case JOB_PROFILE_DETECT_CELEBRITIES:
                    var randomBytes = new byte[16];
                    new Random().NextBytes(randomBytes);
                    var clientToken = randomBytes.HexEncode();

                    var base64JobId = Encoding.UTF8.GetBytes(jobAssignmentId).HexEncode();

                    var rekoParams = new StartCelebrityRecognitionRequest
                    {
                        Video = new Video
                        {
                            S3Object = new Amazon.Rekognition.Model.S3Object
                            {
                                Bucket = inputFile.AwsS3Bucket,
                                Name   = inputFile.AwsS3Key
                            }
                        },
                        ClientRequestToken  = clientToken,
                        JobTag              = base64JobId,
                        NotificationChannel = new NotificationChannel
                        {
                            RoleArn     = REKO_SNS_ROLE_ARN,
                            SNSTopicArn = SNS_TOPIC_ARN
                        }
                    };

                    var rekognitionClient             = new AmazonRekognitionClient();
                    var startCelebRecognitionResponse = await rekognitionClient.StartCelebrityRecognitionAsync(rekoParams);

                    Logger.Debug(startCelebRecognitionResponse.ToMcmaJson().ToString());
                    break;
                }
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);

                try
                {
                    await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "FAILED", ex.ToString());
                }
                catch (Exception innerEx)
                {
                    Logger.Exception(innerEx);
                }
            }
        }
Esempio n. 4
0
        public static async Task ProcessTranscribeJobResultAsync(AwsAiServiceWorkerRequest @event)
        {
            var resourceManager = @event.GetAwsV4ResourceManager();
            var table           = new DynamoDbTable(@event.StageVariables["TableName"]);
            var jobAssignmentId = @event.JobAssignmentId;

            var job = await RetrieveJobAsync(resourceManager, table, jobAssignmentId);

            try
            {
                var jobInput = job.JobInput;

                S3Locator outputLocation;
                if (!jobInput.TryGet <S3Locator>(nameof(outputLocation), out outputLocation))
                {
                    throw new Exception("Invalid or missing output location.");
                }

                var copySource = Uri.EscapeDataString(@event.OutputFile.AwsS3Bucket + "/" + @event.OutputFile.AwsS3Key);

                var s3Bucket = outputLocation.AwsS3Bucket;
                var s3Key    = (!string.IsNullOrWhiteSpace(outputLocation.AwsS3KeyPrefix) ? outputLocation.AwsS3KeyPrefix : string.Empty) + @event.OutputFile.AwsS3Key;

                try
                {
                    var destS3 = await outputLocation.GetClientAsync();

                    await destS3.CopyObjectAsync(new CopyObjectRequest
                    {
                        SourceBucket      = @event.OutputFile.AwsS3Bucket,
                        SourceKey         = @event.OutputFile.AwsS3Key,
                        DestinationBucket = s3Bucket,
                        DestinationKey    = s3Key
                    });
                }
                catch (Exception error)
                {
                    throw new Exception("Unable to copy output file to bucket '" + s3Bucket + "' with key'" + s3Key + "'", error);
                }

                var jobOutput = new JobParameterBag();
                jobOutput["outputFile"] = new S3Locator
                {
                    AwsS3Bucket = s3Bucket,
                    AwsS3Key    = s3Key
                };

                await UpdateJobAssignmentWithOutputAsync(table, jobAssignmentId, jobOutput);
                await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "COMPLETED");
            }
            catch (Exception error)
            {
                Logger.Exception(error);

                try
                {
                    await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "FAILED", error.ToString());
                }
                catch (Exception innerError)
                {
                    Logger.Exception(innerError);
                }
            }

            // Cleanup: Deleting original output file
            try
            {
                var sourceS3 = await @event.OutputFile.GetClientAsync();

                await sourceS3.DeleteObjectAsync(new DeleteObjectRequest
                {
                    BucketName = @event.OutputFile.AwsS3Bucket,
                    Key        = @event.OutputFile.AwsS3Key,
                });
            }
            catch (Exception error)
            {
                Logger.Error("Failed to cleanup transcribe output file.");
                Logger.Exception(error);
            }
        }
        public static async Task ProcessNotificationAsync(AzureAiServiceWorkerRequest @event)
        {
            var jobAssignmentId = @event.JobAssignmentId;

            var resourceManager = @event.GetAwsV4ResourceManager();
            var table           = new DynamoDbTable(@event.StageVariables["TableName"]);
            var azure           = new AzureConfig(@event);

            var azureVideoId = @event.Notification?.Id;
            var azureState   = @event.Notification?.State;

            if (azureVideoId == null || azureState == null)
            {
                Logger.Warn("POST is not coming from Azure Video Indexer. Expected notification to have id and state properties.");
                return;
            }

            try
            {
                var authTokenUrl  = azure.ApiUrl + "/auth/" + azure.Location + "/Accounts/" + azure.AccountID + "/AccessToken?allowEdit=true";
                var customHeaders = new Dictionary <string, string> {
                    ["Ocp-Apim-Subscription-Key"] = azure.SubscriptionKey
                };

                Logger.Debug($"Generate Azure Video Indexer Token: Doing a GET on {authTokenUrl}");
                var mcmaHttp = new McmaHttpClient();
                var response = await mcmaHttp.GetAsync(authTokenUrl, headers : customHeaders).WithErrorHandling();

                var apiToken = await response.Content.ReadAsJsonAsync();

                Logger.Debug($"Azure API Token: {apiToken}");

                var metadataFromAzureVideoIndexer =
                    $"{azure.ApiUrl}/{azure.Location}/Accounts/{azure.AccountID}/Videos/{azureVideoId}/Index?accessToken={apiToken}&language=English";

                Logger.Debug($"Getting Azure video metadata from: {metadataFromAzureVideoIndexer}");
                var indexedVideoMetadataResponse = await mcmaHttp.GetAsync(metadataFromAzureVideoIndexer, headers : customHeaders).WithErrorHandling();

                var videoMetadata = await indexedVideoMetadataResponse.Content.ReadAsJsonAsync();

                Logger.Debug($"Azure AI video metadata: {videoMetadata}");

                //Need to hydrate the destination bucket from the job input
                var workflowJob = await RetrieveJobAsync(resourceManager, table, jobAssignmentId);

                //Retrieve job inputParameters
                var jobInput = workflowJob.JobInput;

                S3Locator outputLocation;
                if (!jobInput.TryGet <S3Locator>(nameof(outputLocation), out outputLocation))
                {
                    throw new Exception("Invalid or missing output location.");
                }

                var jobOutputBucket    = outputLocation.AwsS3Bucket;
                var jobOutputKeyPrefix = outputLocation.AwsS3KeyPrefix != null ? outputLocation.AwsS3KeyPrefix : "";

                // get the info about the destination bucket to store the result of the job
                var s3Params = new PutObjectRequest
                {
                    BucketName  = jobOutputBucket,
                    Key         = jobOutputKeyPrefix + azureVideoId + "-" + Guid.NewGuid() + ".json",
                    ContentBody = videoMetadata.ToString(),
                    ContentType = "application/json"
                };

                var destS3 = await outputLocation.GetClientAsync();

                await destS3.PutObjectAsync(s3Params);

                //updating JobAssignment with jobOutput
                var jobOutput = workflowJob.JobOutput ?? new JobParameterBag();
                jobOutput["outputFile"] = new S3Locator
                {
                    AwsS3Bucket = s3Params.BucketName,
                    AwsS3Key    = s3Params.Key
                };

                await UpdateJobAssignmentWithOutputAsync(table, jobAssignmentId, jobOutput);

                // Setting job assignment status to COMPLETED
                await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "COMPLETED");
            }
            catch (Exception error)
            {
                Logger.Exception(error);

                try
                {
                    await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "FAILED", error.ToString());
                }
                catch (Exception innerEx)
                {
                    Logger.Exception(innerEx);
                }
            }
        }
Esempio n. 6
0
        public async Task <JToken> Handler(JToken @event, ILambdaContext context)
        {
            var resourceManager = AwsEnvironment.GetAwsV4ResourceManager();

            try
            {
                var jobData = new JobBase
                {
                    Status   = "RUNNING",
                    Progress = 63
                };
                await resourceManager.SendNotificationAsync(jobData, @event["notificationEndpoint"].ToMcmaObject <NotificationEndpoint>());
            }
            catch (Exception error)
            {
                Logger.Error("Failed to send notification: {0}", error);
            }

            // get transform job id
            var transformJobId = GetTransformJobId(@event);

            // in case we did not do a transcode, just return the existing essence ID
            if (transformJobId == null)
            {
                return(@event["data"]["bmEssence"].Value <string>());
            }

            //
            var transformJob = await resourceManager.ResolveAsync <TransformJob>(transformJobId);

            S3Locator outputFile;

            if (!transformJob.JobOutput.TryGet <S3Locator>(nameof(outputFile), false, out outputFile))
            {
                throw new Exception("Unable to get outputFile from AmeJob output.");
            }

            var s3Bucket = outputFile.AwsS3Bucket;
            var s3Key    = outputFile.AwsS3Key;

            var bmc = await resourceManager.ResolveAsync <BMContent>(@event["data"]["bmContent"]?.ToString());

            var locator = new S3Locator
            {
                AwsS3Bucket = s3Bucket,
                AwsS3Key    = s3Key
            };

            var bme = CreateBmEssence(bmc, locator);

            bme = await resourceManager.CreateAsync(bme);

            if (bme?.Id == null)
            {
                throw new Exception("Failed to register BMEssence.");
            }

            bmc.BmEssences.Add(bme.Id);

            bmc = await resourceManager.UpdateAsync(bmc);

            return(bme.Id);
        }
Esempio n. 7
0
 private BMEssence CreateBmEssence(BMContent bmContent, S3Locator location)
 => new BMEssence
 {
     BmContent = bmContent.Id,
     Locations = new Locator[] { location }
 };
Esempio n. 8
0
        internal static async Task ProcessJobAssignmentAsync(TransformServiceWorkerRequest @event)
        {
            var resourceManager = @event.Request.GetAwsV4ResourceManager();
            var table           = new DynamoDbTable(@event.Request.StageVariables["TableName"]);
            var jobAssignmentId = @event.JobAssignmentId;

            try
            {
                // 1. Setting job assignment status to RUNNING
                await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "RUNNING", null);

                // 2. Retrieving WorkflowJob
                var transformJob = await RetrieveTransformJobAsync(resourceManager, table, jobAssignmentId);

                // 3. Retrieve JobProfile
                var jobProfile = await RetrieveJobProfileAsync(resourceManager, transformJob);

                // 4. Retrieve job inputParameters
                var jobInput = transformJob.JobInput;

                // 5. Check if we support jobProfile and if we have required parameters in jobInput
                ValidateJobProfile(jobProfile, jobInput);

                switch (jobProfile.Name)
                {
                case JOB_PROFILE_CREATE_PROXY_LAMBDA:
                    S3Locator inputFile;
                    if (!jobInput.TryGet <S3Locator>(nameof(inputFile), out inputFile))
                    {
                        throw new Exception("Invalid or missing input file.");
                    }

                    S3Locator outputLocation;
                    if (!jobInput.TryGet <S3Locator>(nameof(outputLocation), out outputLocation))
                    {
                        throw new Exception("Invalid or missing output location.");
                    }

                    if (string.IsNullOrWhiteSpace(inputFile.AwsS3Bucket) || string.IsNullOrWhiteSpace(inputFile.AwsS3Key))
                    {
                        throw new Exception("Not able to obtain input file");
                    }

                    var data = await inputFile.GetAsync();

                    var localFileName = "/tmp/" + Guid.NewGuid();
                    await data.WriteResponseStreamToFileAsync(localFileName, true, CancellationToken.None);

                    var tempFileName  = "/tmp/" + Guid.NewGuid() + ".mp4";
                    var ffmpegParams  = new[] { "-y", "-i", localFileName, "-preset", "ultrafast", "-vf", "scale=-1:360", "-c:v", "libx264", "-pix_fmt", "yuv420p", tempFileName };
                    var ffmpegProcess = await FFmpegProcess.RunAsync(ffmpegParams);

                    File.Delete(localFileName);

                    var s3Params = new PutObjectRequest
                    {
                        BucketName  = outputLocation.AwsS3Bucket,
                        Key         = (outputLocation.AwsS3KeyPrefix ?? string.Empty) + Guid.NewGuid().ToString() + ".mp4",
                        FilePath    = tempFileName,
                        ContentType = "video/mp4"
                    };

                    var outputS3 = await outputLocation.GetClientAsync();

                    var putResp = await outputS3.PutObjectAsync(s3Params);

                    var jobOutput = new JobParameterBag();
                    jobOutput["outputFile"] = new S3Locator
                    {
                        AwsS3Bucket = s3Params.BucketName,
                        AwsS3Key    = s3Params.Key
                    };

                    await UpdateJobAssignmentWithOutputAsync(table, jobAssignmentId, jobOutput);
                    await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "COMPLETED");

                    break;

                case JOB_PROFILE_CREATE_PROXY_EC2:
                    var ec2hostname = @event.Request.StageVariables["HostnameInstanceEC2"];

                    var ec2Url = "http://" + ec2hostname + "/new-transform-job";

                    var message = new
                    {
                        input = jobInput,
                        notificationEndpoint = new NotificationEndpoint {
                            HttpEndpoint = jobAssignmentId + "/notifications"
                        }
                    };

                    Logger.Debug("Sending to", ec2Url, "message", message);
                    var mcmaHttp = new McmaHttpClient();
                    await mcmaHttp.PostAsJsonAsync(ec2Url, message);

                    Logger.Debug("Done");
                    break;
                }
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);

                try
                {
                    await UpdateJobAssignmentStatusAsync(resourceManager, table, jobAssignmentId, "FAILED", ex.ToString());
                }
                catch (Exception innerEx)
                {
                    Logger.Exception(innerEx);
                }
            }
            finally
            {
                Logger.Debug("Exiting TransformServiceWorker.ProcessJobAssignmentAsync");
            }
        }