public async Task ExecuteAsync(WorkerJobHelper <AIJob> jobHelper)
        {
            S3Locator inputFile;

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

            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-" + jobHelper.JobAssignmentId.Substring(jobHelper.JobAssignmentId.LastIndexOf("/") + 1),
                LanguageCode         = "en-US",
                Media = new Media {
                    MediaFileUri = mediaFileUrl
                },
                MediaFormat      = mediaFormat,
                OutputBucketName = jobHelper.Request.GetRequiredContextVariable("ServiceOutputBucket")
            };

            using (var transcribeService = new AmazonTranscribeServiceClient())
                await transcribeService.StartTranscriptionJobAsync(transcribeParameters);
        }
        public async Task ExecuteAsync(WorkerJobHelper <TransformJob> job)
        {
            S3Locator inputFile;

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

            S3Locator outputLocation;

            if (!job.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);

            job.JobOutput["outputFile"] = new S3Locator
            {
                AwsS3Bucket = s3Params.BucketName,
                AwsS3Key    = s3Params.Key
            };

            await job.CompleteAsync();
        }
예제 #3
0
 public async Task ExecuteAsync(WorkerJobHelper <WorkflowJob> job)
 {
     using (var stepFunctionClient = new AmazonStepFunctionsClient())
         await stepFunctionClient.StartExecutionAsync(
             new StartExecutionRequest
         {
             Input =
                 new
             {
                 Input = job.JobInput,
                 NotificationEndpoint = new NotificationEndpoint {
                     HttpEndpoint = job.JobAssignmentId + "/notifications"
                 }
             }.ToMcmaJson().ToString(),
             StateMachineArn = job.Request.GetRequiredContextVariable($"{job.Profile.Name}Id")
         });
 }
        public async Task ExecuteAsync(WorkerJobHelper <TransformJob> job)
        {
            var ec2hostname = job.Request.GetRequiredContextVariable("HostnameInstanceEC2");

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

            var message = new
            {
                input = job.JobInput,
                notificationEndpoint = new NotificationEndpoint {
                    HttpEndpoint = job.JobAssignmentId + "/notifications"
                }
            };

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

            Logger.Debug("Done");
        }
예제 #5
0
        public async Task ExecuteAsync(WorkerJobHelper <AIJob> jobHelper)
        {
            S3Locator inputFile;

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

            var randomBytes = new byte[16];

            new Random().NextBytes(randomBytes);
            var clientToken = randomBytes.HexEncode();

            var base64JobId = Encoding.UTF8.GetBytes(jobHelper.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     = Environment.GetEnvironmentVariable("REKO_SNS_ROLE_ARN"),
                    SNSTopicArn = Environment.GetEnvironmentVariable("SNS_TOPIC_ARN")
                }
            };

            using (var rekognitionClient = new AmazonRekognitionClient())
                await rekognitionClient.StartCelebrityRecognitionAsync(rekoParams);
        }
예제 #6
0
        public async Task ExecuteAsync(WorkerJobHelper <AmeJob> job)
        {
            S3Locator inputFile;

            if (!job.JobInput.TryGet(nameof(inputFile), out inputFile))
            {
                throw new Exception("Unable to parse input file as S3Locator");
            }

            S3Locator outputLocation;

            if (!job.JobInput.TryGet(nameof(outputLocation), out outputLocation))
            {
                throw new Exception("Unable to parse output location as S3Locator");
            }

            MediaInfoProcess mediaInfoProcess;

            if (inputFile is HttpEndpointLocator httpEndpointLocator && !string.IsNullOrWhiteSpace(httpEndpointLocator.HttpEndpoint))
            {
                Logger.Debug("Running MediaInfo against " + httpEndpointLocator.HttpEndpoint);
                mediaInfoProcess = await MediaInfoProcess.RunAsync("--Output=EBUCore_JSON", httpEndpointLocator.HttpEndpoint);
            }
        public async Task ExecuteAsync(WorkerJobHelper <AIJob> jobHelper)
        {
            S3Locator inputFile;

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

            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}";
            }

            var authTokenUrl  = jobHelper.Request.ApiUrl() + "/auth/" + jobHelper.Request.Location() + "/Accounts/" + jobHelper.Request.AccountID() + "/AccessToken?allowEdit=true";
            var customHeaders = new Dictionary <string, string> {
                ["Ocp-Apim-Subscription-Key"] = jobHelper.Request.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}");

            // call the Azure API to process the video
            // in this scenario the video is located in a public link
            // so no need to upload the file to Azure

            /* Sample URL Structure
             *  https://api.videoindexer.ai/{location}/Accounts/{accountId}/Videos?
             *      accessToken={accessToken}&
             *      name={name}?description={string}&
             *      partition={string}&
             *      externalId={string}&
             *      callbackUrl={string}&
             *      metadata={string}&
             *      language={string}&
             *      videoUrl={string}&
             *      fileName={string}&
             *      indexingPreset={string}&
             *      streamingPreset=Default&
             *      linguisticModelId={string}&
             *      privacy={string}&
             *      externalUrl={string}" */

            var secureHost    = new Uri(jobHelper.JobAssignmentId, UriKind.Absolute).Host;
            var nonSecureHost = new Uri(jobHelper.Request.GetRequiredContextVariable("PublicUrlNonSecure"), UriKind.Absolute).Host;

            var callbackUrl = Uri.EscapeDataString(jobHelper.JobAssignmentId.Replace(secureHost, nonSecureHost) + "/notifications");

            var postVideoUrl = jobHelper.Request.ApiUrl() + "/" + jobHelper.Request.Location() + "/Accounts/" + jobHelper.Request.AccountID() + "/Videos?accessToken=" + apiToken + "&name=" + inputFile.AwsS3Key + "&callbackUrl=" + callbackUrl + "&videoUrl=" + mediaFileUrl + "&fileName=" + inputFile.AwsS3Key;

            Logger.Debug($"Call Azure Video Indexer API: Doing a POST on {postVideoUrl}");
            var postVideoResponse = await mcmaHttp.PostAsync(postVideoUrl, null, customHeaders).WithErrorHandling();

            var azureAssetInfo = await postVideoResponse.Content.ReadAsJsonAsync();

            Logger.Debug("azureAssetInfo: ", azureAssetInfo);

            try
            {
                jobHelper.JobOutput["jobInfo"] = azureAssetInfo;

                await jobHelper.UpdateJobAssignmentOutputAsync();
            }
            catch (Exception error)
            {
                Logger.Error("Error updating the job", error);
            }
        }
예제 #8
0
        protected override async Task ExecuteAsync(WorkerRequest request, ProcessRekognitionResult requestInput)
        {
            var workerJobHelper =
                new WorkerJobHelper <AIJob>(
                    DbTableProvider.Table(request.TableName()),
                    ResourceManagerProvider.GetResourceManager(request),
                    request,
                    requestInput.JobAssignmentId);

            try
            {
                await workerJobHelper.InitializeAsync();

                var jobInput = workerJobHelper.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   = requestInput.JobInfo.RekoJobId;
                var rekoJobType = requestInput.JobInfo.RekoJobType;
                var status      = requestInput.JobInfo.Status;

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

                object data = null;
                switch (rekoJobType)
                {
                case "StartCelebrityRecognition":
                    using (var rekognitionClient = new AmazonRekognitionClient())
                        data = await rekognitionClient.GetCelebrityRecognitionAsync(new GetCelebrityRecognitionRequest
                        {
                            JobId      = rekoJobId, /* required */
                            MaxResults = 1000000,
                            SortBy     = "TIMESTAMP"
                        });
                    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);
                }

                workerJobHelper.JobOutput["outputFile"] = new S3Locator
                {
                    AwsS3Bucket = s3Bucket,
                    AwsS3Key    = newS3Key
                };

                await workerJobHelper.CompleteAsync();
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
                try
                {
                    await workerJobHelper.FailAsync(ex.ToString());
                }
                catch (Exception innerEx)
                {
                    Logger.Exception(innerEx);
                }
            }
        }
 public Task ExecuteAsync(WorkerJobHelper <AIJob> job)
 => throw new NotImplementedException($"{Name} profile has not yet been implemented for Azure.");
예제 #10
0
        protected override async Task ExecuteAsync(WorkerRequest request, ProcessNotificationRequest requestInput)
        {
            var azureVideoId = requestInput.Notification?.Id;
            var azureState = requestInput.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;
            }

            var workerJobHelper =
                new WorkerJobHelper<AIJob>(
                    DbTableProvider.Table(request.TableName()),
                    ResourceManagerProvider.GetResourceManager(request),
                    request,
                    requestInput.JobAssignmentId);

            try
            {
                await workerJobHelper.InitializeAsync();

                var authTokenUrl = request.ApiUrl() + "/auth/" + request.Location() + "/Accounts/" + request.AccountID() + "/AccessToken?allowEdit=true";
                var customHeaders = new Dictionary<string, string> { ["Ocp-Apim-Subscription-Key"] = request.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 =
                    $"{request.ApiUrl()}/{request.Location()}/Accounts/{request.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}");
                
                S3Locator outputLocation;
                if (!workerJobHelper.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
                workerJobHelper.JobOutput["outputFile"] = new S3Locator
                {
                    AwsS3Bucket = s3Params.BucketName,
                    AwsS3Key = s3Params.Key
                };

                await workerJobHelper.CompleteAsync();
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
                try
                {
                    await workerJobHelper.FailAsync(ex.ToString());
                }
                catch (Exception innerEx)
                {
                    Logger.Exception(innerEx);
                }
            }
        }
        public async Task ExecuteAsync(WorkerJobHelper <AIJob> jobHelper)
        {
            S3Locator inputFile;

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

            S3Locator outputLocation;

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

            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 = jobHelper.JobInput.TryGet("sourceLanguageCode", out string srcLanguageCode) ? srcLanguageCode : "auto",
                TargetLanguageCode = jobHelper.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);

            jobHelper.JobOutput.Set("outputFile", new S3Locator
            {
                AwsS3Bucket = s3Params.BucketName,
                AwsS3Key    = s3Params.Key
            });

            await jobHelper.CompleteAsync();
        }
    }
        protected override async Task ExecuteAsync(WorkerRequest request, ProcessTranscribeJobResult requestInput)
        {
            var workerJobHelper =
                new WorkerJobHelper <AIJob>(
                    DbTableProvider.Table(request.TableName()),
                    ResourceManagerProvider.GetResourceManager(request),
                    request,
                    requestInput.JobAssignmentId);

            try
            {
                await workerJobHelper.InitializeAsync();

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

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

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

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

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

                workerJobHelper.JobOutput["outputFile"] = new S3Locator
                {
                    AwsS3Bucket = s3Bucket,
                    AwsS3Key    = s3Key
                };

                await workerJobHelper.CompleteAsync();
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
                try
                {
                    await workerJobHelper.FailAsync(ex.ToString());
                }
                catch (Exception innerEx)
                {
                    Logger.Exception(innerEx);
                }
            }

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

                await sourceS3.DeleteObjectAsync(new DeleteObjectRequest
                {
                    BucketName = requestInput.OutputFile.AwsS3Bucket,
                    Key        = requestInput.OutputFile.AwsS3Key,
                });
            }
            catch (Exception error)
            {
                Logger.Error("Failed to cleanup transcribe output file.");
                Logger.Exception(error);
            }
        }