Files
monorepo/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/LCU.Webapps.Marketing.SPIT/Services/TextToSpeechService.cs
T
2026-04-20 09:53:07 -05:00

109 lines
5.0 KiB
C#

using System;
using System.Threading.Tasks;
using Microsoft.CognitiveServices.Speech;
using Serilog;
using LCU.Webapps.Marketing.SPIT.Model;
using LCU.Api.Internal.FileOperationsLib.Models;
namespace LCU.Webapps.Marketing.SPIT.Services
{
public class TextToSpeechService
{
private readonly SpitConfiguration _spitConfiguration;
private readonly IFileOperationsApiService _fileOperationsApiService;
private SpeechConfig _speechConfig;
public TextToSpeechService(SpitConfiguration spitConfiguration, IFileOperationsApiService fileOperationsApiService)
{
_spitConfiguration = spitConfiguration;
_fileOperationsApiService = fileOperationsApiService;
_speechConfig = SpeechConfig.FromSubscription(_spitConfiguration.SubscriptionKey, _spitConfiguration.Region);
}
public async Task<string> SpeechToFile(TextToSpeech textToSpeech)
{
try
{
_speechConfig.SpeechSynthesisVoiceName = textToSpeech.SelectedVoiceShortName;
var finalDestination = (_spitConfiguration.FileDestination ?? string.Empty).Trim();
if (string.IsNullOrWhiteSpace(finalDestination))
{
Log.Error("FileDestination is not configured.");
return string.Empty;
}
Log.Information(
"Starting speech synthesis for file save. Voice={Voice}, Region={Region}, FileName={FileName}, Extension={Extension}, Destination={Destination}, SsmlLength={SsmlLength}",
textToSpeech.SelectedVoiceShortName,
_spitConfiguration.Region,
textToSpeech.FileName,
_spitConfiguration.FileExtention,
finalDestination,
textToSpeech.Ssml?.Length ?? 0);
using var synth = new SpeechSynthesizer(_speechConfig);
using var result = await synth.SpeakSsmlAsync(textToSpeech.Ssml);
if (result.Reason != ResultReason.SynthesizingAudioCompleted)
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(result);
Log.Error(
"Speech synthesis failed. Reason={Reason}, CancellationReason={CancellationReason}, CancellationErrorCode={CancellationErrorCode}, ResultId={ResultId}, ErrorDetails={ErrorDetails}",
result.Reason,
cancellation?.Reason,
cancellation?.ErrorCode,
result.ResultId,
cancellation?.ErrorDetails);
return string.Empty;
}
if (result.AudioData == null || result.AudioData.Length == 0)
{
Log.Error("Speech synthesis returned no audio data. ResultId={ResultId}", result.ResultId);
return string.Empty;
}
Log.Information(
"Speech synthesis completed successfully. ResultId={ResultId}, AudioBytes={AudioBytes}",
result.ResultId,
result.AudioData.Length);
var writeRequest = new WriteFileRequest
{
DestinationPath = finalDestination,
FileName = textToSpeech.FileName,
Extension = _spitConfiguration.FileExtention,
FileData = Convert.ToBase64String(result.AudioData),
Overwrite = true,
};
Log.Information(
"Writing synthesized audio file via FileOperations API. FileName={FileName}, Extension={Extension}, Destination={Destination}, AudioBytes={AudioBytes}",
textToSpeech.FileName,
_spitConfiguration.FileExtention,
finalDestination,
result.AudioData.Length);
var written = await _fileOperationsApiService.WriteFileAsync(writeRequest);
Log.Information(
"FileOperations API write completed. Success={Written}, FileName={FileName}, Destination={Destination}",
written,
textToSpeech.FileName,
finalDestination);
return written ? finalDestination : string.Empty;
}
catch (Exception ex)
{
Log.Error(ex,
"Failure saving synthesized speech file. Voice={Voice}, Region={Region}, FileName={FileName}, Extension={Extension}, Destination={Destination}, SsmlLength={SsmlLength}",
textToSpeech?.SelectedVoiceShortName,
_spitConfiguration.Region,
textToSpeech?.FileName,
_spitConfiguration.FileExtention,
_spitConfiguration.FileDestination,
textToSpeech?.Ssml?.Length ?? 0);
return "";
}
}
}
}