Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
310 changes: 66 additions & 244 deletions Tests/Resgrid.Tests/Web/Tts/S3StorageServiceTests.cs

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions Tests/Resgrid.Tests/Web/Tts/TtsServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ public void create_espeak_start_info_should_use_mbrola_profile_for_english_voice
"-v",
"mb-us1",
"-s",
"130",
"140",
"-p",
"50",
"-g",
"3");
"2");
}

[Test]
Expand Down Expand Up @@ -308,7 +308,8 @@ private static AudioProcessingService CreateService()
{
return new AudioProcessingService(
Options.Create(new TtsOptions()),
Mock.Of<ILogger<AudioProcessingService>>());
Mock.Of<ILogger<AudioProcessingService>>(),
Mock.Of<ITextPreprocessor>());
}

private static T InvokePrivateMethod<T>(object instance, string methodName, params object[] arguments)
Expand Down
1,114 changes: 557 additions & 557 deletions Web/Resgrid.Web.Services/Resgrid.Web.Services.xml

Large diffs are not rendered by default.

39 changes: 1 addition & 38 deletions Web/Resgrid.Web.Tts/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -106,12 +103,8 @@ await context.HttpContext.Response.WriteAsJsonAsync(
};
});

builder.Services.AddSingleton<IAmazonS3>(sp =>
{
var options = sp.GetRequiredService<IOptions<S3StorageOptions>>().Value;
return CreateS3Client(options);
});
builder.Services.AddSingleton<IStorageService, S3StorageService>();
builder.Services.AddSingleton<ITextPreprocessor, TextPreprocessor>();
builder.Services.AddSingleton<ICacheService, CacheService>();
builder.Services.AddSingleton<IAudioProcessingService, AudioProcessingService>();
builder.Services.AddSingleton<ITtsPlaybackUrlService, TtsPlaybackUrlService>();
Expand Down Expand Up @@ -156,34 +149,4 @@ await context.HttpContext.Response.WriteAsJsonAsync(

app.Run();

static AmazonS3Client CreateS3Client(S3StorageOptions options)
{
var credentials = new BasicAWSCredentials(options.AccessKey, options.SecretKey);
var config = new AmazonS3Config
{
ForcePathStyle = options.ForcePathStyle,
AuthenticationRegion = options.Region
};

if (!string.IsNullOrWhiteSpace(options.Endpoint))
{
if (Uri.TryCreate(options.Endpoint, UriKind.Absolute, out var endpointUri))
{
config.ServiceURL = endpointUri.GetLeftPart(UriPartial.Authority);
config.UseHttp = endpointUri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase);
}
else
{
config.ServiceURL = $"{(options.UseSsl ? Uri.UriSchemeHttps : Uri.UriSchemeHttp)}://{options.Endpoint}";
config.UseHttp = !options.UseSsl;
}
}
else
{
config.RegionEndpoint = RegionEndpoint.GetBySystemName(options.Region);
}

return new AmazonS3Client(credentials, config);
}

public partial class Program;
1 change: 0 additions & 1 deletion Web/Resgrid.Web.Tts/Resgrid.Web.Tts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AWSSDK.S3" Version="3.7.414.5" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.2" />
<PackageReference Include="Sentry.AspNetCore" Version="5.4.0" />
<PackageReference Include="Sentry.Profiling" Version="5.4.0" />
Expand Down
12 changes: 8 additions & 4 deletions Web/Resgrid.Web.Tts/Services/AudioProcessingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ namespace Resgrid.Web.Tts.Services
public sealed class AudioProcessingService : IAudioProcessingService
{
private const string MbrolaEnglishVoice = "mb-us1";
private const int MbrolaEnglishSpeed = 130;
private const int MbrolaEnglishSpeed = 140;
private const int MbrolaEnglishPitch = 50;
private const int MbrolaEnglishWordGap = 3;
private const int MbrolaEnglishWordGap = 2;
private const string TelephoneAudioFilter = "highpass=f=200, lowpass=f=3000, anequalizer=c0 f=2500 w=1000 g=3 t=1";

private readonly TtsOptions _options;
private readonly ILogger<AudioProcessingService> _logger;
private readonly ITextPreprocessor _textPreprocessor;

public AudioProcessingService(
IOptions<TtsOptions> options,
ILogger<AudioProcessingService> logger)
ILogger<AudioProcessingService> logger,
ITextPreprocessor textPreprocessor)
{
_options = options.Value;
_logger = logger;
_textPreprocessor = textPreprocessor;
}

public async Task<byte[]> GenerateNormalizedWavAsync(string text, string voice, int speed, CancellationToken cancellationToken)
Expand All @@ -36,7 +39,8 @@ public async Task<byte[]> GenerateNormalizedWavAsync(string text, string voice,

try
{
await RunEspeakAsync(text, voice, speed, rawFilePath, cancellationToken);
var preprocessedText = _textPreprocessor.Preprocess(text, voice);
await RunEspeakAsync(preprocessedText, voice, speed, rawFilePath, cancellationToken);
await RunFfmpegAsync(rawFilePath, normalizedFilePath, cancellationToken);

return await File.ReadAllBytesAsync(normalizedFilePath, cancellationToken);
Expand Down
15 changes: 15 additions & 0 deletions Web/Resgrid.Web.Tts/Services/ITextPreprocessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Resgrid.Web.Tts.Services
{
/// <summary>
/// Preprocesses dispatch text before it is sent to the TTS engine so that
/// common abbreviations, codes, and jargon are spoken intelligibly.
/// </summary>
public interface ITextPreprocessor
{
/// <summary>
/// Normalises the input text for the given voice / language so that eSpeak
/// (or any downstream TTS engine) produces the most natural speech.
/// </summary>
string Preprocess(string text, string voice);
}
}
Loading
Loading