Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
OoLunar committed Dec 19, 2023
1 parent fbb98c8 commit 177bdac
Show file tree
Hide file tree
Showing 22 changed files with 358 additions and 17 deletions.
2 changes: 1 addition & 1 deletion examples/LivestreamApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static async Task Main(string[] args)

transcriptionApi.OnErrorReceived += (connection, errorEventArgs) =>
{
Console.WriteLine(errorEventArgs.Error);
Console.WriteLine(errorEventArgs.Exception);
return Task.CompletedTask;
};

Expand Down
7 changes: 7 additions & 0 deletions src/AsyncEvents/AsyncEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ namespace DeepgramSharp.AsyncEvents
/// </summary>
public abstract class AsyncEvent
{
/// <summary>
/// The name of the event.
/// </summary>
public string Name { get; }

/// <summary>
/// Initializes a new instance of the <see cref="AsyncEvent"/> class.
/// </summary>
/// <param name="name">The name of the event.</param>
protected internal AsyncEvent(string name) => Name = name;
}
}
22 changes: 22 additions & 0 deletions src/DeepgramClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

namespace DeepgramSharp
{
/// <summary>
/// Represents the Deepgram API.
/// </summary>
public sealed class DeepgramClient
{
internal static readonly JsonSerializerOptions DefaultJsonSerializerOptions = new(JsonSerializerDefaults.Web)
Expand All @@ -19,11 +22,24 @@ public sealed class DeepgramClient

private static readonly string _defaultUserAgent = $"DeepgramSharp/{typeof(DeepgramClient).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "0.1.0"}";

/// <summary>
/// The base URI to use for requests.
/// </summary>
public Uri BaseUri { get; init; }

/// <summary>
/// The <see cref="DeepgramPreRecordedApi"/> to used for transcribing prerecorded audio.
/// </summary>
public DeepgramPreRecordedApi PreRecordedApi { get; init; }
internal readonly ILogger<DeepgramClient> Logger;
private readonly AuthenticationHeaderValue _authenticationHeader;

/// <summary>
/// Creates a new <see cref="DeepgramClient"/> and connects to the Deepgram prerecorded API.
/// </summary>
/// <param name="apiKey">The API key to use for requests.</param>
/// <param name="baseUri">The URI to use for requests. Overwrites the default Uri, <see cref="DeepgramRoutes.PrerecordedUri"/>.</param>
/// <param name="logger">The <see cref="ILogger{TCategoryName}"/> to use for logging.</param>
public DeepgramClient(string apiKey, Uri? baseUri = null, ILogger<DeepgramClient>? logger = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(apiKey, nameof(apiKey));
Expand All @@ -33,6 +49,12 @@ public DeepgramClient(string apiKey, Uri? baseUri = null, ILogger<DeepgramClient
BaseUri = baseUri ?? DeepgramRoutes.PrerecordedUri;
}

/// <summary>
/// Creates a new <see cref="DeepgramLivestreamApi"/> and connects to the Deepgram livestream API.
/// </summary>
/// <param name="options">The options to use for the livestream.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to use for the request.</param>
/// <returns>A <see cref="DeepgramLivestreamApi"/> connected to the Deepgram livestream API.</returns>
public async ValueTask<DeepgramLivestreamApi> CreateLivestreamAsync(DeepgramLivestreamOptionCollection? options = null, CancellationToken cancellationToken = default)
{
DeepgramLivestreamApi api = new(this, BaseUri);
Expand Down
50 changes: 48 additions & 2 deletions src/DeepgramLivestreamApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace DeepgramSharp
{
/// <summary>
/// Represents a connection to the Deepgram livestream API.
/// </summary>
public sealed class DeepgramLivestreamApi(DeepgramClient client, Uri? baseUri = null) : IDisposable
{
private sealed class AuthenticatedMessageInvoker : HttpMessageInvoker
Expand Down Expand Up @@ -49,29 +52,60 @@ public override HttpResponseMessage Send(HttpRequestMessage request, Cancellatio
Type = DeepgramPayloadType.CloseStream.ToString()
}, DeepgramClient.DefaultJsonSerializerOptions);

// Metadata
/// <summary>
/// Raised when the livestream receives metadata from the Deepgram API.
/// </summary>
public event AsyncEventHandler<DeepgramLivestreamApi, DeepgramLivestreamMetadataReceivedEventArgs> OnMetadataReceived { add => _metadataReceived.Register(value); remove => _metadataReceived.Unregister(value); }
private readonly AsyncEvent<DeepgramLivestreamApi, DeepgramLivestreamMetadataReceivedEventArgs> _metadataReceived = new("METADATA_RECEIVED", EverythingWentWrongErrorHandler);

/// <summary>
/// Raised when the livestream receives a transcription from the Deepgram API.
/// </summary>
public event AsyncEventHandler<DeepgramLivestreamApi, DeepgramLivestreamTranscriptReceivedEventArgs> OnTranscriptionReceived { add => _transcriptionReceived.Register(value); remove => _transcriptionReceived.Unregister(value); }
private readonly AsyncEvent<DeepgramLivestreamApi, DeepgramLivestreamTranscriptReceivedEventArgs> _transcriptionReceived = new("TRANSCRIPTION_RECEIVED", EverythingWentWrongErrorHandler);

/// <summary>
/// Raised when an error occurs within the Deepgram API.
/// </summary>
public event AsyncEventHandler<DeepgramLivestreamApi, DeepgramLivestreamErrorEventArgs> OnErrorReceived { add => _errorReceived.Register(value); remove => _errorReceived.Unregister(value); }
private readonly AsyncEvent<DeepgramLivestreamApi, DeepgramLivestreamErrorEventArgs> _errorReceived = new("ERROR_RECEIVED", EverythingWentWrongErrorHandler);

/// <summary>
/// Raised when the livestream is closed by the Deepgram API.
/// </summary>
public event AsyncEventHandler<DeepgramLivestreamApi, DeepgramLivestreamClosedEventArgs> OnClosed { add => _closed.Register(value); remove => _closed.Unregister(value); }
private readonly AsyncEvent<DeepgramLivestreamApi, DeepgramLivestreamClosedEventArgs> _closed = new("CLOSED", EverythingWentWrongErrorHandler);

/// <summary>
/// The <see cref="DeepgramClient"/> to use for requests.
/// </summary>
public DeepgramClient Client { get; init; } = client ?? throw new ArgumentNullException(nameof(client));

/// <summary>
/// The URI to use for requests.
/// </summary>
public Uri BaseUri { get; init; } = baseUri ?? DeepgramRoutes.LivestreamUri;

/// <summary>
/// The underlying <see cref="ClientWebSocket"/> used for communication with the Deepgram API.
/// </summary>
public ClientWebSocket WebSocket { get; init; } = new();

/// <summary>
/// The current state of the <see cref="WebSocket"/>.
/// </summary>
public WebSocketState State => WebSocket.State;

private readonly SemaphoreSlim _semaphore = new(1, 1);
private Memory<byte> _buffer = new byte[512];
private DateTimeOffset _lastKeepAlive = DateTimeOffset.Now;
private bool _isDisposed;

/// <summary>
/// Connects to the Deepgram livestream API.
/// </summary>
/// <param name="options">The options to use for the connection.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to use for the connection.</param>
public async ValueTask ConnectAsync(DeepgramLivestreamOptionCollection? options = null, CancellationToken cancellationToken = default)
{
if (WebSocket.State == WebSocketState.Open)
Expand All @@ -88,6 +122,12 @@ await WebSocket.ConnectAsync(new UriBuilder(BaseUri)
_ = ReceiveTranscriptionLoopAsync();
}

/// <summary>
/// Sends audio to the Deepgram livestream API.
/// </summary>
/// <param name="audioFrames">A <see cref="ReadOnlyMemory{T}"/> containing the raw audio to send.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to use for the request.</param>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
public async ValueTask SendAudioAsync(ReadOnlyMemory<byte> audioFrames, CancellationToken cancellationToken = default)
{
if (WebSocket.State != WebSocketState.Open)
Expand All @@ -99,6 +139,11 @@ public async ValueTask SendAudioAsync(ReadOnlyMemory<byte> audioFrames, Cancella
_lastKeepAlive = DateTimeOffset.UtcNow;
}

/// <summary>
/// Let's the Deepgram livestream API know that you are done sending audio.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to use for the request.</param>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
public async ValueTask CloseAsync(CancellationToken cancellationToken = default)
{
if (WebSocket.State == WebSocketState.Closed)
Expand Down Expand Up @@ -184,7 +229,7 @@ private async Task ReceiveTranscriptionLoopAsync()
JsonDocument document = JsonDocument.Parse(_buffer[..(int)error.BytePositionInLine]);
_ = _errorReceived.InvokeAsync(this, new()
{
Error = new DeepgramWebsocketException(document)
Exception = new DeepgramWebsocketException(document)
});
}
finally
Expand All @@ -194,6 +239,7 @@ private async Task ReceiveTranscriptionLoopAsync()
}
}

/// <inheritdoc cref="IDisposable.Dispose"/>
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Expand Down
2 changes: 1 addition & 1 deletion src/DeepgramLivestreamOptionCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace DeepgramSharp
public sealed record DeepgramLivestreamOptionCollection : DeepgramOptionCollection
{
/// <summary>
/// Indicates whether the streaming endpoint should send you updates to its transcription as more audio becomes available. When set to <see cref="true"/>, the streaming endpoint returns regular updates, which means transcription results will likely change for a period of time. By default, this flag is set to <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/interim-results"/>
/// Indicates whether the streaming endpoint should send you updates to its transcription as more audio becomes available. When set to <see langword="true"/>, the streaming endpoint returns regular updates, which means transcription results will likely change for a period of time. By default, this flag is set to <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/interim-results"/>
/// </summary>
public bool InterimResults { get => bool.Parse(_options[nameof(InterimResults)]); set => _options[nameof(InterimResults)] = value.ToString().ToLowerInvariant(); }

Expand Down
15 changes: 9 additions & 6 deletions src/DeepgramOptionCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ namespace DeepgramSharp
/// </summary>
public record DeepgramOptionCollection : IDictionary<string, string>
{
/// <summary>
/// The underlying dictionary of options.
/// </summary>
protected readonly Dictionary<string, string> _options = [];

/// <summary>
Expand All @@ -39,12 +42,12 @@ public record DeepgramOptionCollection : IDictionary<string, string>
public CultureInfo Language { get => CultureInfo.GetCultureInfoByIetfLanguageTag(_options[nameof(Language)]); set => _options[nameof(Language)] = value.IetfLanguageTag; }

/// <summary>
/// Add punctuation and capitalization to the transcript. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/punctuation" />
/// Add punctuation and capitalization to the transcript. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/punctuation" />
/// </summary>
public bool Punctuate { get => bool.Parse(_options[nameof(Punctuate)]); set => _options[nameof(Punctuate)] = value.ToString().ToLowerInvariant(); }

/// <summary>
/// Remove profanity from the transcript. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/profanity-filter" />
/// Remove profanity from the transcript. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/profanity-filter" />
/// </summary>
public bool ProfanityFilter { get => bool.Parse(_options[nameof(ProfanityFilter)]); set => _options[nameof(ProfanityFilter)] = value.ToString().ToLowerInvariant(); }

Expand All @@ -59,22 +62,22 @@ public record DeepgramOptionCollection : IDictionary<string, string>
public bool Diarize { get => bool.Parse(_options[nameof(Diarize)]); set => _options[nameof(Diarize)] = value.ToString().ToLowerInvariant(); }

/// <summary>
/// Version of the diarization feature to use. Only used when <see cref="Diarize"/> is <see cref="true"/>. Default: <c>latest</c>. Learn more: <see href="https://developers.deepgram.com/docs/diarization#enable-feature" />
/// Version of the diarization feature to use. Only used when <see cref="Diarize"/> is <see langword="true"/>. Default: <c>latest</c>. Learn more: <see href="https://developers.deepgram.com/docs/diarization#enable-feature" />
/// </summary>
public string DiarizeVersion { get => Uri.UnescapeDataString(_options[nameof(DiarizeVersion)]); set => _options[nameof(DiarizeVersion)] = Uri.EscapeDataString(value); }

/// <summary>
/// Apply formatting to transcript output. When set to true, additional formatting will be applied to transcripts to improve readability. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/smart-format" />
/// Apply formatting to transcript output. When set to true, additional formatting will be applied to transcripts to improve readability. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/smart-format" />
/// </summary>
public bool SmartFormat { get => bool.Parse(_options[nameof(SmartFormat)]); set => _options[nameof(SmartFormat)] = value.ToString().ToLowerInvariant(); }

/// <summary>
/// Whether to include words like "uh" and "um" in transcription output. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/filler-words" />
/// Whether to include words like "uh" and "um" in transcription output. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/filler-words" />
/// </summary>
public bool FillerWords { get => bool.Parse(_options[nameof(FillerWords)]); set => _options[nameof(FillerWords)] = value.ToString().ToLowerInvariant(); }

/// <summary>
/// Transcribe each audio channel independently. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/multichannel" />
/// Transcribe each audio channel independently. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/multichannel" />
/// </summary>
public bool MultiChannel { get => bool.Parse(_options[nameof(MultiChannel)]); set => _options[nameof(MultiChannel)] = value.ToString().ToLowerInvariant(); }

Expand Down
23 changes: 23 additions & 0 deletions src/DeepgramPrerecordedApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,32 @@

namespace DeepgramSharp
{
/// <summary>
/// Represents the Deepgram prerecorded API.
/// </summary>
/// <param name="client">The <see cref="DeepgramClient"/> to use for requests.</param>
/// <param name="baseUri">The URI to use for requests. Overwrites the default Uri, <see cref="DeepgramRoutes.PrerecordedUri"/>.</param>
public sealed class DeepgramPreRecordedApi(DeepgramClient client, Uri? baseUri = null)
{
private static readonly HttpClient HttpClient = new();

/// <summary>
/// The URI to use for requests.
/// </summary>
public Uri BaseUri { get; init; } = baseUri ?? DeepgramRoutes.PrerecordedUri;

/// <summary>
/// The <see cref="DeepgramClient"/> to use for requests.
/// </summary>
public DeepgramClient Client { get; init; } = client ?? throw new ArgumentNullException(nameof(client));

/// <summary>
/// Transcribes the audio from the given stream.
/// </summary>
/// <param name="audioStream">The stream containing the audio to transcribe.</param>
/// <param name="options">A collection of options to use for the request.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to use for the request.</param>
/// <returns>A <see cref="DeepgramTranscription"/> containing the transcription.</returns>
public ValueTask<DeepgramTranscription?> TranscribeAsync(Stream audioStream, DeepgramPrerecordedApiOptionCollection? options = null, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(audioStream);
Expand All @@ -30,6 +49,10 @@ public sealed class DeepgramPreRecordedApi(DeepgramClient client, Uri? baseUri =
return TranscribeAsync(request, cancellationToken);
}

/// <inheritdoc cref="TranscribeAsync(Stream, DeepgramPrerecordedApiOptionCollection?, CancellationToken)"/>
/// <param name="url">The URL that Deepgram should use to download the audio.</param>
/// <param name="options">A collection of options to use for the request.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to use for the request.</param>
public ValueTask<DeepgramTranscription?> TranscribeAsync(Uri url, DeepgramPrerecordedApiOptionCollection? options = null, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(url);
Expand Down
6 changes: 3 additions & 3 deletions src/DeepgramPrerecordedApiOptionCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public sealed record DeepgramPrerecordedApiOptionCollection : DeepgramOptionColl
public bool DetectLanguage { get => bool.Parse(_options[nameof(DetectLanguage)]); set => _options[nameof(DetectLanguage)] = value.ToString().ToLowerInvariant(); }

/// <summary>
/// Split audio into paragraphs. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/paragraphs" />
/// Split audio into paragraphs. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/paragraphs" />
/// </summary>
public bool Paragraphs { get => bool.Parse(_options[nameof(Paragraphs)]); set => _options[nameof(Paragraphs)] = value.ToString().ToLowerInvariant(); }

Expand All @@ -24,12 +24,12 @@ public sealed record DeepgramPrerecordedApiOptionCollection : DeepgramOptionColl
public string Summarize { get => Uri.UnescapeDataString(_options[nameof(Summarize)]); set => _options[nameof(Summarize)] = Uri.EscapeDataString(value); }

/// <summary>
/// Identify and extract key topics. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/topic-detection" />
/// Identify and extract key topics. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/topic-detection" />
/// </summary>
public bool DetectTopics { get => bool.Parse(_options[nameof(DetectTopics)]); set => _options[nameof(DetectTopics)] = value.ToString().ToLowerInvariant(); }

/// <summary>
/// Segment speech into meaningful units based on gaps in speech. Default: <see cref="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/utterances"/>
/// Segment speech into meaningful units based on gaps in speech. Default: <see langword="false"/>. Learn more: <see href="https://developers.deepgram.com/docs/utterances"/>
/// </summary>
public bool Utterances { get => bool.Parse(_options[nameof(Utterances)]); set => _options[nameof(Utterances)] = value.ToString().ToLowerInvariant(); }

Expand Down
Loading

0 comments on commit 177bdac

Please sign in to comment.