From f71bbb72223fe1e84a9a03b73cf7c91cd80b386d Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Mon, 20 Apr 2026 15:23:11 +0000 Subject: [PATCH] Updating --- .../Model/SpitConfiguration.cs | 25 ++++++++++++++++++- .../Pages/Index.razor | 7 +++++- .../LCU.Webapps.Marketing.SPIT/Program.cs | 4 ++- .../Services/AuthenticationService.cs | 19 ++++++++++---- .../Services/TextToSpeechService.cs | 14 ++++++++++- .../Services/VoiceService.cs | 15 ++++++++--- .../appsettings.json | 2 ++ .../wwwroot/js/SpeechFunctions.js | 10 +++++--- .../normal/set_secrets_deployment.yaml | 18 ++++++++++++- .../normal/set_secrets_provider.yaml | 9 ++++++- 10 files changed, 105 insertions(+), 18 deletions(-) diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Model/SpitConfiguration.cs b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Model/SpitConfiguration.cs index 7eba141..299dcc4 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Model/SpitConfiguration.cs +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Model/SpitConfiguration.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace LCU.Webapps.Marketing.SPIT.Model { @@ -8,6 +9,8 @@ namespace LCU.Webapps.Marketing.SPIT.Model public string SeqApiKey { get; set; } public string SeqUrl { get; set; } public string SubscriptionKey { get; set; } + public string SpeechApiKey { get; set; } + public string SpeechEndpoint { get; set; } public string FetchTokenUri { get; set; } public string VoicesUrl { get; set; } public string OcpApimSubscriptionKey { get; set; } @@ -17,5 +20,25 @@ namespace LCU.Webapps.Marketing.SPIT.Model public string SpitRoles { get; set; } public string DefaultLanguageWithCountryCode { get; set; } public List EnabledLanguageOptionCodes { get; set; } + + public string ResolveSpeechSubscriptionKey() + { + return string.IsNullOrWhiteSpace(SpeechApiKey) ? SubscriptionKey : SpeechApiKey; + } + + public bool HasSpeechEndpoint() + { + return !string.IsNullOrWhiteSpace(SpeechEndpoint); + } + + public Uri ResolveSpeechEndpointUri() + { + if (!HasSpeechEndpoint()) + { + return null; + } + + return new Uri(SpeechEndpoint.Trim(), UriKind.Absolute); + } } } diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Pages/Index.razor b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Pages/Index.razor index 68b2a93..39679d3 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Pages/Index.razor +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Pages/Index.razor @@ -214,7 +214,12 @@ return; } - await JSRuntime.InvokeVoidAsync("synthesizeSpeech", spitConfiguration.SubscriptionKey, spitConfiguration.Region, _textToSpeech.Ssml); + await JSRuntime.InvokeVoidAsync( + "synthesizeSpeech", + spitConfiguration.ResolveSpeechSubscriptionKey(), + spitConfiguration.Region, + spitConfiguration.SpeechEndpoint, + _textToSpeech.Ssml); } public void OpenDirectory(string fileDestination) diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Program.cs b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Program.cs index 01094c2..a0d3799 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Program.cs +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Program.cs @@ -19,8 +19,10 @@ namespace LCU.Webapps.Marketing.SPIT { builder.AddJsonFile("/app/config/environment-appsettings/appsettings.json", optional: true, reloadOnChange: true); builder.AddJsonFile("/app/config/workload-appsettings/appsettings.json", optional: true, reloadOnChange: true); - builder.AddJsonFile("/vault/secrets/lcu-webapps-marketing-spit-seq-api-key.json", optional: true, reloadOnChange: true); + builder.AddJsonFile("/vault/secrets/spit-seq-api-key.json", optional: true, reloadOnChange: true); builder.AddJsonFile("/vault/secrets/spit-primary-subscription-key.json", optional: true, reloadOnChange: true); + builder.AddJsonFile("/vault/secrets/speech-api-key.json", optional: true, reloadOnChange: true); + builder.AddJsonFile("/vault/secrets/speech-endpoint.json", optional: true, reloadOnChange: true); builder.AddJsonFile("/vault/secrets/spit-azuread-client-id.json", optional: true, reloadOnChange: true); builder.AddJsonFile("/vault/secrets/spit-azuread-client-secret.json", optional: true, reloadOnChange: true); }) diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/AuthenticationService.cs b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/AuthenticationService.cs index a28378e..4fed640 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/AuthenticationService.cs +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/AuthenticationService.cs @@ -17,13 +17,22 @@ public class AuthenticationService public async Task FetchTokenAsync() { - UriBuilder uriBuilder = new($"https://{_spitConfiguration.Region}.{_spitConfiguration.FetchTokenUri}"); - var uri = uriBuilder.Uri; + var uri = BuildTokenUri(); var client = _lcuHttpClient.CreateClient(uri); - client.DefaultRequestHeaders.Add(_spitConfiguration.OcpApimSubscriptionKey, _spitConfiguration.SubscriptionKey); + client.DefaultRequestHeaders.Add(_spitConfiguration.OcpApimSubscriptionKey, _spitConfiguration.ResolveSpeechSubscriptionKey()); - var result = await client.PostAsync(uriBuilder.Uri.AbsoluteUri, null); + var result = await client.PostAsync(uri.AbsoluteUri, null); return await result.Content.ReadAsStringAsync(); } -} \ No newline at end of file + + private Uri BuildTokenUri() + { + if (_spitConfiguration.HasSpeechEndpoint()) + { + return new Uri(_spitConfiguration.ResolveSpeechEndpointUri(), "/sts/v1.0/issueToken"); + } + + return new Uri($"https://{_spitConfiguration.Region}.{_spitConfiguration.FetchTokenUri}"); + } +} diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/TextToSpeechService.cs b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/TextToSpeechService.cs index 184a73b..4978bf5 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/TextToSpeechService.cs +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/TextToSpeechService.cs @@ -17,7 +17,7 @@ namespace LCU.Webapps.Marketing.SPIT.Services { _spitConfiguration = spitConfiguration; _fileOperationsApiService = fileOperationsApiService; - _speechConfig = SpeechConfig.FromSubscription(_spitConfiguration.SubscriptionKey, _spitConfiguration.Region); + _speechConfig = BuildSpeechConfig(); } public async Task SpeechToFile(TextToSpeech textToSpeech) @@ -104,5 +104,17 @@ namespace LCU.Webapps.Marketing.SPIT.Services return ""; } } + + private SpeechConfig BuildSpeechConfig() + { + var subscriptionKey = _spitConfiguration.ResolveSpeechSubscriptionKey(); + + if (_spitConfiguration.HasSpeechEndpoint()) + { + return SpeechConfig.FromEndpoint(_spitConfiguration.ResolveSpeechEndpointUri(), subscriptionKey); + } + + return SpeechConfig.FromSubscription(subscriptionKey, _spitConfiguration.Region); + } } } diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/VoiceService.cs b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/VoiceService.cs index ca61e81..e38b537 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/VoiceService.cs +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/VoiceService.cs @@ -29,15 +29,14 @@ namespace LCU.Webapps.Marketing.SPIT.Services try { - UriBuilder uriBuilder = new UriBuilder($"https://{_spitConfiguration.Region}{_spitConfiguration.VoicesUrl}"); - var uri = uriBuilder.Uri; + var uri = BuildVoicesUri(); var token = await _authenticationService.FetchTokenAsync(); var client = _lcuHttpClient.CreateClient(uri); client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}"); - var result = await client.GetAsync(uriBuilder.Uri.AbsoluteUri); + var result = await client.GetAsync(uri.AbsoluteUri); var jsonString = await result.Content.ReadAsStringAsync(); voices = JsonConvert.DeserializeObject>(jsonString); } @@ -48,5 +47,15 @@ namespace LCU.Webapps.Marketing.SPIT.Services return voices; } + + private Uri BuildVoicesUri() + { + if (_spitConfiguration.HasSpeechEndpoint()) + { + return new Uri(_spitConfiguration.ResolveSpeechEndpointUri(), "/cognitiveservices/voices/list"); + } + + return new Uri($"https://{_spitConfiguration.Region}{_spitConfiguration.VoicesUrl}"); + } } } diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/appsettings.json b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/appsettings.json index 6b60a07..d69447c 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/appsettings.json +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/appsettings.json @@ -5,6 +5,8 @@ "SeqApiKey": "VALUE-IN-KEYVAULT", "SeqUrl": "https://qa-seq.lcu-internal.com", "SubscriptionKey": "VALUE-IN-KEYVAULT", + "SpeechApiKey": "VALUE-IN-KEYVAULT", + "SpeechEndpoint": "VALUE-IN-KEYVAULT", "FetchTokenUri": "api.cognitive.microsoft.com/sts/v1.0/issueToken", "VoicesUrl": ".tts.speech.microsoft.com/cognitiveservices/voices/list", "OcpApimSubscriptionKey": "Ocp-Apim-Subscription-Key", diff --git a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/wwwroot/js/SpeechFunctions.js b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/wwwroot/js/SpeechFunctions.js index e44ba0c..388f615 100644 --- a/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/wwwroot/js/SpeechFunctions.js +++ b/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/wwwroot/js/SpeechFunctions.js @@ -1,12 +1,14 @@ -function synthesizeSpeech(subscriptionKey, region, ssml) { +function synthesizeSpeech(subscriptionKey, region, endpoint, ssml) { var SpeechSDK; if (!!window.SpeechSDK) { SpeechSDK = window.SpeechSDK; } - const speechConfig = SpeechSDK.SpeechConfig.fromSubscription(subscriptionKey, region); + const speechConfig = endpoint + ? SpeechSDK.SpeechConfig.fromEndpoint(new URL(endpoint), subscriptionKey) + : SpeechSDK.SpeechConfig.fromSubscription(subscriptionKey, region); const audioConfig = SpeechSDK.AudioConfig.fromDefaultSpeakerOutput(); - const synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig, audioConfig); + let synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig, audioConfig); synthesizer.speakSsmlAsync( ssml, @@ -21,4 +23,4 @@ function synthesizeSpeech(subscriptionKey, region, ssml) { synthesizer.close(); synthesizer = undefined; }); -} \ No newline at end of file +} diff --git a/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml b/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml index c4578cf..2cf4d4b 100644 --- a/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml +++ b/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml @@ -24,6 +24,22 @@ readOnly: true subPath: spit-primary-subscription-key +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: spit-secrets + mountPath: /vault/secrets/speech-api-key.json + readOnly: true + subPath: speech-api-key + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: spit-secrets + mountPath: /vault/secrets/speech-endpoint.json + readOnly: true + subPath: speech-endpoint + - op: add path: /spec/template/spec/containers/0/volumeMounts/- value: @@ -38,4 +54,4 @@ name: spit-secrets mountPath: /vault/secrets/spit-azuread-client-secret.json readOnly: true - subPath: spit-azuread-client-secret \ No newline at end of file + subPath: spit-azuread-client-secret diff --git a/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_provider.yaml b/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_provider.yaml index ea6c7a5..3de0fbc 100644 --- a/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_provider.yaml +++ b/LCU.Webapps.Marketing.SPIT/kustomize/components/keyvaults/normal/set_secrets_provider.yaml @@ -10,6 +10,14 @@ objectName: spit-primary-subscription-key objectType: secret objectVersion: "" + - | + objectName: speech-api-key + objectType: secret + objectVersion: "" + - | + objectName: speech-endpoint + objectType: secret + objectVersion: "" - | objectName: spit-azuread-client-id objectType: secret @@ -18,4 +26,3 @@ objectName: spit-azuread-client-secret objectType: secret objectVersion: "" -