private async Task TranscribeAndPersist(SrStoredEpisode storedEpisode, SpeechBatchClient speechBatchClient)
        {
            _logger.LogInformation($"Transcribing episode {storedEpisode.Episode.Id}...");
            var episodeTranscriptionId = await TranscribeEpisode(storedEpisode, speechBatchClient);

            var episodeTranscription = await WaitForTranscription(episodeTranscriptionId, storedEpisode, speechBatchClient);

            _logger.LogInformation($"Transcribed episode {storedEpisode.Episode.Id}...");

            if (episodeTranscription == null)
            {
                return;
            }

            _logger.LogInformation($"Transfer transcribed episode {storedEpisode.Episode.Id}...");
            var storedEpisodeTranscription = await TransferTranscribedEpisode(episodeTranscription, storedEpisode);

            await speechBatchClient.DeleteTranscriptionAsync(episodeTranscriptionId);

            var transcriptionResult = await GetTranscriptionResult(storedEpisodeTranscription, storedEpisodeTranscription.TranscriptionResultChannel0BlobIdentifier);

            await StoreTranscriptionResult(storedEpisode, transcriptionResult, storedEpisodeTranscription);

            _logger.LogInformation($"Transfered transcribed episode {storedEpisode.Episode.Id}...");
        }
        private async Task <Guid> TranscribeEpisode(SrStoredEpisode storedEpisode, SpeechBatchClient speechBatchClient)
        {
            var audioUrl = RemoveQueryString(storedEpisode.AudioUrl);
            var transcriptionDefinition = TranscriptionDefinition.Create(
                $"RadioText - Episode {storedEpisode.Episode.Id}",
                "RadioText",
                storedEpisode.AudioLocale,
                new Uri(audioUrl)
                );

            var transcriptionLocation = await speechBatchClient.PostTranscriptionAsync(transcriptionDefinition);

            return(GetTranscriptionGuid(transcriptionLocation));
        }
 public RoundRobinSpeechBatchClientFactory(List <SpeechBatchClientOptions> options)
 {
     _clients = options.Select(x => SpeechBatchClient.CreateApiV2Client(x.Key, x.Hostname, x.Port)).ToArray();
 }
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var services = builder.Services;

            services.AddTransient <ISverigesRadioApiClient>(s => SverigesRadioApiClient.CreateClient());

            services.AddTransient(x =>
            {
                var configuration  = x.GetRequiredService <IConfiguration>();
                var storageAccount = CloudStorageAccount.Parse(configuration["AzureStorage:BlobsConnectionString"]);
                return(storageAccount.CreateCloudBlobClient());
            });

            services.AddTransient(x =>
            {
                var configuration  = x.GetRequiredService <IConfiguration>();
                var storageAccount = Microsoft.Azure.Cosmos.Table.CloudStorageAccount.Parse(configuration["AzureStorage:TablesConnectionString"]);
                return(storageAccount.CreateCloudTableClient(new TableClientConfiguration()));
            });

            services.AddTransient(x =>
            {
                var configuration = x.GetRequiredService <IConfiguration>();
                return(SpeechConfig.FromSubscription(configuration["AzureSpeech:Key"], configuration["AzureSpeech:Region"]));
            });
            services.AddTransient(x =>
            {
                var configuration = x.GetRequiredService <IConfiguration>();
                return(SpeechBatchClient.CreateApiV2Client(configuration["AzureSpeech:Key"], configuration["AzureSpeech:Hostname"], 443));
            });

            services.AddTransient(x =>
            {
                var configuration = x.GetRequiredService <IConfiguration>();
                var credentials   = new ApiKeyServiceClientCredentials(configuration["AzureTextAnalytics:Key"]);
                return(new TextAnalyticsClient(credentials)
                {
                    Endpoint = configuration["AzureTextAnalytics:Endpoint"]
                });
            });

            services.AddTransient(x =>
            {
                var configuration = x.GetRequiredService <IConfiguration>();
                return(TranslatorClient.CreateClient(configuration["AzureTranslator:Key"], configuration["AzureTranslator:Endpoint"]));
            });

            services.AddTransient <IStorageTransfer, AzureStorageTransfer>();
            services.AddTransient <IStorage, AzureTableStorage>(s =>
            {
                var configuration = s.GetRequiredService <IConfiguration>();
                return(new AzureTableStorage(
                           s.GetRequiredService <CloudTableClient>(),
                           configuration["AzureStorage:EpisodeStatusesTableName"],
                           configuration["AzureStorage:EpisodesTableName"],
                           configuration["AzureStorage:EpisodeTranscriptionsTableName"],
                           configuration["AzureStorage:EpisodeTextAnalyticsTableName"],
                           configuration["AzureStorage:EpisodeSpeechTableName"]
                           ));
            });

            services.AddTransient <ISummaryStorage, SummaryAzureTableStorage>(s =>
            {
                var configuration = s.GetRequiredService <IConfiguration>();
                return(new SummaryAzureTableStorage(
                           s.GetRequiredService <CloudTableClient>(),
                           configuration["AzureStorage:EpisodeSummaryTableName"]
                           ));
            });

            services.AddTransient <SrEpisodesLister>();
            services.AddTransient(s =>
            {
                var configuration = s.GetRequiredService <IConfiguration>();
                return(new SrEpisodeCollector(
                           configuration["AzureStorage:AudioContainerName"],
                           s.GetRequiredService <IStorageTransfer>(),
                           s.GetRequiredService <ISverigesRadioApiClient>(),
                           s.GetRequiredService <ILogger <SrEpisodeCollector> >(),
                           s.GetRequiredService <IStorage>()
                           ));
            });

            services.AddTransient(s =>
            {
                var configuration = s.GetRequiredService <IConfiguration>();
                return(new SrEpisodeTranscriber(
                           configuration["AzureStorage:EpisodeTranscriptionsContainerName"],
                           s.GetRequiredService <ISpeechBatchClientFactory>(),
                           s.GetRequiredService <IStorageTransfer>(),
                           s.GetRequiredService <ILogger <SrEpisodeCollector> >(),
                           s.GetRequiredService <IStorage>(),
                           s.GetRequiredService <CloudBlobClient>()
                           ));
            });

            services.AddTransient <SrEpisodeTextEnricher>();
            services.AddTransient <SrEpisodeSummarizer>();
            services.AddTransient(s =>
            {
                var configuration = s.GetRequiredService <IConfiguration>();
                return(new SrEpisodeSpeaker(
                           configuration["AzureStorage:EpisodeSpeechContainerName"],
                           s.GetRequiredService <ISpeechConfigFactory>(),
                           s.GetRequiredService <IStorage>(),
                           s.GetRequiredService <ILogger <SrEpisodeSpeaker> >(),
                           s.GetRequiredService <CloudBlobClient>()
                           ));
            });

            services.AddTransient <SrWorker>();
        }
        private async Task <Transcription?> WaitForTranscription(Guid transcriptionId, SrStoredEpisode storedEpisode, SpeechBatchClient speechBatchClient)
        {
            while (true)
            {
                var transcription = await speechBatchClient.GetTranscriptionAsync(transcriptionId);

                _logger.LogTrace($"Transcribing status for {storedEpisode.Episode.Id} is {transcription.Status}");

                switch (transcription.Status)
                {
                case "":
                case "Failed":
                    _logger.LogError($"Error transcribing {storedEpisode.Episode.Id}: {transcription.StatusMessage}");
                    throw new Exception($"Error transcribing {storedEpisode.Episode.Id}: {transcription.StatusMessage}");

                case "Succeeded":
                    _logger.LogInformation($"Transcribed {storedEpisode.Episode.Id}");
                    return(transcription);

                case "NotStarted":
                case "Running":
                    break;
                }

                await Task.Delay(WaitBetweenStatusCheck);
            }
        }