109 lines
5.0 KiB
C#
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 "";
|
|
}
|
|
}
|
|
}
|
|
}
|