We are trying to create a college project(unified TTS portal) where customer can come and select their respective provider( Google, Amazon Polly) and provide their access key and secret key for respective provider.

Once configuration is configured, there is one api /texttospeach, in which they will just pass the config Id and text which service needs to convert it to speach and return the response.

Here service task is

  1. Read the configuration from DB using Config Id.
  2. Identify provider (Google, Amazon Polly)
  3. Create respective provider class object based provider identified and then provider class will Build the provider client and call respective TTS api.

As we can see in below code we are building the TextToSpeechClient _client for each request. Is this a good approach? Please suggest.

public class GoogleCloudTextToSpeechVendorAsync : TTSVendor
{

    private TextToSpeechClient _client;
    private GoogleTTSConfig _googleTTSConfig;

    public GoogleCloudTextToSpeechVendorAsync(GoogleTTSConfig googleTTSConfig)
    {
        this._googleTTSConfig = googleTTSConfig;
    }

    /// <summary>
    /// 
    /// </summary>
    public async Task BuildAsync()
    {
        byte[] byteArray = Convert.FromBase64String(this._googleTTSConfig.Base64ServiceAccount);
        var serviceAccount = Encoding.UTF8.GetString(byteArray);
    
        serviceAccount = serviceAccount.Replace(@"\\", @"\");
        GoogleCredential googleCred = GoogleCredential.FromJson(serviceAccount.ToString());

        ChannelCredentials channelCreds = googleCred.ToChannelCredentials();
        TextToSpeechClientBuilder clientBuilder = new TextToSpeechClientBuilder()
        {
            ChannelCredentials = channelCreds,
            Endpoint = "texttospeech.googleapis.com"
        };
        _client = await clientBuilder.BuildAsync();
    }

    public async Task<byte[]> TrySpeak(string voiceName, string textToSpeak) 
    {
        var input = new SynthesisInput();
        input.Text = textToSpeak;
        VoiceSelectionParams voiceSelection = new VoiceSelectionParams();
        voiceSelection.Name = voiceName;
        voiceSelection.SsmlGender = SsmlVoiceGender.Unspecified;

        AudioConfig audioConfig = new AudioConfig();
        audioConfig.SampleRateHertz = 8000;
        audioConfig.AudioEncoding = AudioEncoding.Linear16;

        var synthesizeSpeechResponse = await _client.SynthesizeSpeechAsync(input, voiceSelection, audioConfig);
        return synthesizeSpeechResponse.AudioContent.ToByteArray();
    }
}

NA

1

There are 1 best solutions below

0
StepUp On

As we can see in below code we are building the TextToSpeechClient _client for each request. Is this a good approach? Please suggest.

I believe if various providers should be called, then you need to call a corresponding provider. It is possible to implement by applying Strategy pattern. It is also enhances separation of concerns. What I mean is one class has just one goal.

Let's imagine we have some various Providers that should be called based on type.

So code of user input would look like this:

public enum ProviderType
{
    Google, Amazon, Polly
}

And abstract class of BaseProvider would look like this:

public abstract class BaseProvider
{
    public DateTime StartDateTime { get; set; } = DateTime.Now;

    public abstract string Build();
}

and concrete implementations would like this:

public class GoogleProvider : BaseProvider
{
    public override string Build() => 
        "I am a GoogleProvider. Object created: " + StartDateTime.ToString();
}

public class AmazonProvider : BaseProvider
{
    public override string Build() => 
        "I am a AmazonProvider. Object created: " + StartDateTime.ToString();
}

And then ProviderFactory would look like this:

public class ProviderFactory
{
    private Dictionary<ProviderType, BaseProvider> _ProviderByType;

    public ProviderFactory()
    {
        _ProviderByType = new Dictionary<ProviderType, BaseProvider>()
        {
            { ProviderType.Google, new GoogleProvider() },
            { ProviderType.Amazon, new AmazonProvider() }
        };
    }

    public BaseProvider GetInstance(ProviderType providerType) => 
        _ProviderByType[providerType];
}