Skip to content

Instantly share code, notes, and snippets.

@simonziegler
Created February 2, 2023 08:50
Show Gist options
  • Save simonziegler/dbb10e287c889ad7d76b0fcc98a29ffb to your computer and use it in GitHub Desktop.
Save simonziegler/dbb10e287c889ad7d76b0fcc98a29ffb to your computer and use it in GitHub Desktop.
ASP.NET Speech Recognition Service
using Microsoft.CognitiveServices.Speech;
namespace UtilityNamespace;
/// <summary>
/// A service interface to recognize speech. Intended to be used as a transient service.
/// </summary>
public interface ISpeechRecognizerService
{
/// <summary>
/// A continuous speech recognition session.
/// </summary>
public interface ISession : IDisposable
{
/// <summary>
/// Stops the session and returns the final speech recognition result. Also disposes of the session, so can only be called once and will throw an exception if called again.
/// </summary>
/// <returns></returns>
public Task<SpeechRecognitionResult> EndSession();
}
/// <summary>
///
/// </summary>
/// <param name="receiveRecognizingText">Action that recevies text that is in the process of being recognized</param>
/// <param name="receiveRecognizedText">Action that receives fully recognized/decoded text</param>
/// <returns></returns>
public Task<ISession> StartNewSession(Func<string, Task> receiveRecognizingText, Func<string, Task> receiveRecognizedText);
}
using Microsoft.CognitiveServices.Speech;
using Microsoft.Extensions.Configuration;
using System;
using System.Threading.Tasks;
using UtilityNamespace;
namespace AppNamespace;
/// <summary>
/// Implements <see cref="ISpeechRecognizerService"/> for UK English using Microsoft Azure speech recognition services.
/// </summary>
public class SpeechRecognizerService : ISpeechRecognizerService
{
private class Session : ISpeechRecognizerService.ISession
{
private SpeechRecognizer SpeechRecognizer { get; set; }
private SpeechRecognitionResult SpeechRecognitionResult { get; set; }
private TaskCompletionSource<int> StopRecognition { get; set; }
private bool Disposed { get; set; }
public static async Task<ISpeechRecognizerService.ISession> CreateSession(IConfiguration configuration, Func<string, Task> receiveRecognizingText, Func<string, Task> receiveRecognizedText)
{
var speechConfig = SpeechConfig.FromSubscription(configuration["SpeechRecognition:SubscriptionKey"], configuration["SpeechRecognition:Region"]);
speechConfig.SpeechRecognitionLanguage = configuration["SpeechRecognition:Language"];
speechConfig.EnableDictation();
speechConfig.SetProfanity(ProfanityOption.Removed);
Session session = new()
{
SpeechRecognizer = new(speechConfig),
StopRecognition = new(TaskCreationOptions.RunContinuationsAsynchronously),
};
// Subscribes to events.
session.SpeechRecognizer.Recognizing += (s, e) =>
{
receiveRecognizingText(e.Result.Text);
};
session.SpeechRecognizer.Recognized += (s, e) =>
{
receiveRecognizedText(e.Result.Text);
session.SpeechRecognitionResult = e.Result;
};
session.SpeechRecognizer.Canceled += (s, e) =>
{
session.StopRecognition.TrySetResult(0);
};
session.SpeechRecognizer.SessionStopped += (s, e) =>
{
session.StopRecognition.TrySetResult(0);
};
// Starts continuous recognition. Uses StopContinuousRecognitionAsync() to stop recognition.
await session.SpeechRecognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);
return session;
}
public async Task<SpeechRecognitionResult> EndSession()
{
if (Disposed)
{
throw new ObjectDisposedException(GetType().Name);
}
// Stops recognition.
await SpeechRecognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
// Waits for completion.
// Use Task.WaitAny to keep the task rooted.
Task.WaitAny(new[] { StopRecognition.Task });
Dispose();
return SpeechRecognitionResult;
}
protected virtual void Dispose(bool disposing)
{
if (!Disposed)
{
if (disposing)
{
SpeechRecognizer.Dispose();
}
Disposed = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
private readonly IConfiguration _configuration;
public SpeechRecognizerService(IConfiguration configuration)
{
_configuration = configuration;
}
public Task<ISpeechRecognizerService.ISession> StartNewSession(Func<string, Task> receiveRecognizingText, Func<string, Task> receiveRecognizedText)
{
return Session.CreateSession(_configuration, receiveRecognizingText, receiveRecognizedText);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment