Skip to content
Tracon

ISpeechDialogueSynthesizer

Namespace Tracon · Assembly Tracon.Abstractions.dll

A speech provider that voices a dialogue: an ordered list of turns, each spoken by its own voice, in one request and one audio result.

public interface ISpeechDialogueSynthesizer

A capability next to ISpeechSynthesizer, not a part of it: a provider that speaks one voice per request implements no dialogue member. The same instance implements both interfaces, and it is registered as an ISpeechSynthesizer (the unnamed default, or by name with AddSpeechSynthesizer). It is not registered as ISpeechDialogueSynthesizer: a caller takes the capability from ISpeechProviderResolver.GetDialogueSynthesizerAsync, which applies the tenant’s checks first.

Splitting is the caller’s job. A request that exceeds ISpeechDialogueSynthesizer.DialogueCapabilities is refused before the service is called; the implementation never splits or truncates a dialogue. The caller plans its requests from SpeechDialogueCapabilities.MaxVoices and SpeechDialogueCapabilities.MaxCharactersPerRequest, and joins the audio itself.

DI lifetime — singleton. The capability lives on the synthesizer instance, which is a container singleton; it holds no per-call state.

Tenant behavior — TENANT-INDEPENDENT implementation, tenant-gated calls. The instance never reads the tenant. ISpeechProviderResolver applies the tenant’s egress policy to ISpeechDialogueSynthesizer.ProviderName and passes the tenant’s own credential in SpeechDialogueRequest.Credential, only to an implementation whose ISpeechDialogueSynthesizer.SupportsTenantCredentials is true.

Delivery: no delivery guarantee applies. One call is one request to the provider; it is not retried here, and a failed call produces no audio.

A workflow function node that voices two turns with the default synthesizer:

tracon.AddWorkflowFunction<List<ChatMessage>, List<ChatMessage>>(
"two-voices",
provider =>
{
var speech = provider.GetRequiredService<ISpeechProviderResolver>();
return async (messages, context, cancellationToken) =>
{
var dialogue = await speech.GetDialogueSynthesizerAsync(cancellationToken: cancellationToken);
var result = await dialogue.SynthesizeDialogueAsync(
new SpeechDialogueRequest
{
Turns =
[
new SpeechDialogueTurn { Text = "Welcome back.", VoiceId = "host-voice" },
new SpeechDialogueTurn { Text = "Glad to be here.", VoiceId = "guest-voice" },
],
IncludeTimestamps = true,
},
cancellationToken);
var timing = new List<string>();
foreach (var segment in result.Segments ?? [])
{
timing.Add($"turn {segment.TurnIndex}: {segment.Start} - {segment.End}");
}
return [new ChatMessage(ChatRole.Assistant, string.Join(", ", timing))];
};
});

Gets the limits of one dialogue request.

SpeechDialogueCapabilities DialogueCapabilities { get; }

SpeechDialogueCapabilities

The provider name. Used in cost records and in the tenant’s checks.

string ProviderName { get; }

string

A tenant’s egress policy and provider bindings name this value, not the name the synthesizer was registered under.

Gets whether the implementation honours a tenant credential passed in SpeechDialogueRequest.Credential.

bool SupportsTenantCredentials { get; }

bool

The default is false. Tracon then refuses a dialogue for a tenant that has its own binding for ISpeechDialogueSynthesizer.ProviderName rather than make it on the configured credential, which would bill the wrong account. An implementation that returns true uses the credential for the call it came with and never falls back to its configured one.

SynthesizeDialogueAsync(SpeechDialogueRequest, CancellationToken)

Section titled “ SynthesizeDialogueAsync(SpeechDialogueRequest, CancellationToken)”

Voices a dialogue.

ValueTask<SpeechDialogueAudio> SynthesizeDialogueAsync(SpeechDialogueRequest request, CancellationToken cancellationToken = default)

request SpeechDialogueRequest

The turns and the settings.

cancellationToken CancellationToken

The cancellation token.

ValueTask<SpeechDialogueAudio>

The audio of the whole dialogue and, when requested, each turn’s time range.

ArgumentNullException

request is null.

TraconException

The request breaks a limit of ISpeechDialogueSynthesizer.DialogueCapabilities, a turn has no text or no voice, a provider setting is unknown or has the wrong type, or the provider answered with an error. The service is not called for the first three. The message names the limit or the key, never a turn’s text or a setting’s value.

NotSupportedException

SpeechDialogueRequest.Credential is set and ISpeechDialogueSynthesizer.SupportsTenantCredentials is false.