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
Original file line number Diff line number Diff line change
Expand Up @@ -180,19 +180,26 @@ partial void ProcessAccountsMeTtsApiKeysPartialUpdateResponseContent(
/// Your LMNT API key.<br/>
/// https://app.lmnt.com/account#api-keys
/// </param>
/// <param name="google">
/// A service account JSON key for your Google Cloud project with the Text-to-Speech API enabled.<br/>
/// https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#before-you-begin<br/>
/// https://cloud.google.com/iam/docs/keys-create-delete#creating
/// </param>
/// <param name="cancellationToken">The token to cancel the operation with</param>
/// <exception cref="global::System.InvalidOperationException"></exception>
public async global::System.Threading.Tasks.Task<global::Ultravox.AccountTtsKeys> AccountsMeTtsApiKeysPartialUpdateAsync(
string? elevenLabs = default,
string? cartesia = default,
string? lmnt = default,
string? google = default,
global::System.Threading.CancellationToken cancellationToken = default)
{
var __request = new global::Ultravox.PatchedSetTtsApiKeysRequest
{
ElevenLabs = elevenLabs,
Cartesia = cartesia,
Lmnt = lmnt,
Google = google,
};

return await AccountsMeTtsApiKeysPartialUpdateAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ public partial interface IAccountsClient
/// Your LMNT API key.<br/>
/// https://app.lmnt.com/account#api-keys
/// </param>
/// <param name="google">
/// A service account JSON key for your Google Cloud project with the Text-to-Speech API enabled.<br/>
/// https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#before-you-begin<br/>
/// https://cloud.google.com/iam/docs/keys-create-delete#creating
/// </param>
/// <param name="cancellationToken">The token to cancel the operation with</param>
/// <exception cref="global::System.InvalidOperationException"></exception>
global::System.Threading.Tasks.Task<global::Ultravox.AccountTtsKeys> AccountsMeTtsApiKeysPartialUpdateAsync(
string? elevenLabs = default,
string? cartesia = default,
string? lmnt = default,
string? google = default,
global::System.Threading.CancellationToken cancellationToken = default);
}
}
320 changes: 162 additions & 158 deletions src/libs/Ultravox/Generated/Ultravox.JsonSerializerContextTypes.g.cs

Large diffs are not rendered by default.

13 changes: 12 additions & 1 deletion src/libs/Ultravox/Generated/Ultravox.Models.AccountTtsKeys.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public sealed partial class AccountTtsKeys
[global::System.Text.Json.Serialization.JsonPropertyName("lmnt")]
public global::Ultravox.KeyPrefix? Lmnt { get; set; }

/// <summary>
/// The Google service account key.
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("google")]
public global::Ultravox.KeyPrefix? Google { get; set; }

/// <summary>
/// Additional properties that are not explicitly defined in the schema
/// </summary>
Expand All @@ -44,17 +50,22 @@ public sealed partial class AccountTtsKeys
/// <param name="lmnt">
/// The LMNT API key.
/// </param>
/// <param name="google">
/// The Google service account key.
/// </param>
#if NET7_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
#endif
public AccountTtsKeys(
global::Ultravox.KeyPrefix? elevenLabs,
global::Ultravox.KeyPrefix? cartesia,
global::Ultravox.KeyPrefix? lmnt)
global::Ultravox.KeyPrefix? lmnt,
global::Ultravox.KeyPrefix? google)
{
this.ElevenLabs = elevenLabs;
this.Cartesia = cartesia;
this.Lmnt = lmnt;
this.Google = google;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ public sealed partial class PatchedSetTtsApiKeysRequest
[global::System.Text.Json.Serialization.JsonPropertyName("lmnt")]
public string? Lmnt { get; set; }

/// <summary>
/// A service account JSON key for your Google Cloud project with the Text-to-Speech API enabled.<br/>
/// https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#before-you-begin<br/>
/// https://cloud.google.com/iam/docs/keys-create-delete#creating
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("google")]
public string? Google { get; set; }

/// <summary>
/// Additional properties that are not explicitly defined in the schema
/// </summary>
Expand All @@ -50,17 +58,24 @@ public sealed partial class PatchedSetTtsApiKeysRequest
/// Your LMNT API key.<br/>
/// https://app.lmnt.com/account#api-keys
/// </param>
/// <param name="google">
/// A service account JSON key for your Google Cloud project with the Text-to-Speech API enabled.<br/>
/// https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#before-you-begin<br/>
/// https://cloud.google.com/iam/docs/keys-create-delete#creating
/// </param>
#if NET7_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
#endif
public PatchedSetTtsApiKeysRequest(
string? elevenLabs,
string? cartesia,
string? lmnt)
string? lmnt,
string? google)
{
this.ElevenLabs = elevenLabs;
this.Cartesia = cartesia;
this.Lmnt = lmnt;
this.Google = google;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ public sealed partial class UltravoxV1ExternalVoice
[global::System.Text.Json.Serialization.JsonPropertyName("lmnt")]
public global::Ultravox.UltravoxV1LmntVoice? Lmnt { get; set; }

/// <summary>
/// A voice served by Google, using bidirectional streaming.<br/>
/// (For non-streaming or output-only streaming, use generic.)
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("google")]
public global::Ultravox.UltravoxV1GoogleVoice? Google { get; set; }

/// <summary>
/// A voice served by a generic REST-based TTS API.
/// </summary>
Expand All @@ -53,6 +60,10 @@ public sealed partial class UltravoxV1ExternalVoice
/// <param name="lmnt">
/// A voice served by LMNT.
/// </param>
/// <param name="google">
/// A voice served by Google, using bidirectional streaming.<br/>
/// (For non-streaming or output-only streaming, use generic.)
/// </param>
/// <param name="generic">
/// A voice served by a generic REST-based TTS API.
/// </param>
Expand All @@ -63,11 +74,13 @@ public UltravoxV1ExternalVoice(
global::Ultravox.UltravoxV1ElevenLabsVoice? elevenLabs,
global::Ultravox.UltravoxV1CartesiaVoice? cartesia,
global::Ultravox.UltravoxV1LmntVoice? lmnt,
global::Ultravox.UltravoxV1GoogleVoice? google,
global::Ultravox.UltravoxV1GenericVoice? generic)
{
this.ElevenLabs = elevenLabs;
this.Cartesia = cartesia;
this.Lmnt = lmnt;
this.Google = google;
this.Generic = generic;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#nullable enable

namespace Ultravox
{
public sealed partial class UltravoxV1GoogleVoice
{
/// <summary>
/// Serializes the current instance to a JSON string using the provided JsonSerializerContext.
/// </summary>
public string ToJson(
global::System.Text.Json.Serialization.JsonSerializerContext jsonSerializerContext)
{
return global::System.Text.Json.JsonSerializer.Serialize(
this,
this.GetType(),
jsonSerializerContext);
}

/// <summary>
/// Serializes the current instance to a JSON string using the provided JsonSerializerOptions.
/// </summary>
#if NET8_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
[global::System.Diagnostics.CodeAnalysis.RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")]
#endif
public string ToJson(
global::System.Text.Json.JsonSerializerOptions? jsonSerializerOptions = null)
{
return global::System.Text.Json.JsonSerializer.Serialize(
this,
jsonSerializerOptions);
}

/// <summary>
/// Deserializes a JSON string using the provided JsonSerializerContext.
/// </summary>
public static global::Ultravox.UltravoxV1GoogleVoice? FromJson(
string json,
global::System.Text.Json.Serialization.JsonSerializerContext jsonSerializerContext)
{
return global::System.Text.Json.JsonSerializer.Deserialize(
json,
typeof(global::Ultravox.UltravoxV1GoogleVoice),
jsonSerializerContext) as global::Ultravox.UltravoxV1GoogleVoice;
}

/// <summary>
/// Deserializes a JSON string using the provided JsonSerializerOptions.
/// </summary>
#if NET8_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
[global::System.Diagnostics.CodeAnalysis.RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")]
#endif
public static global::Ultravox.UltravoxV1GoogleVoice? FromJson(
string json,
global::System.Text.Json.JsonSerializerOptions? jsonSerializerOptions = null)
{
return global::System.Text.Json.JsonSerializer.Deserialize<global::Ultravox.UltravoxV1GoogleVoice>(
json,
jsonSerializerOptions);
}

/// <summary>
/// Deserializes a JSON stream using the provided JsonSerializerContext.
/// </summary>
public static async global::System.Threading.Tasks.ValueTask<global::Ultravox.UltravoxV1GoogleVoice?> FromJsonStreamAsync(
global::System.IO.Stream jsonStream,
global::System.Text.Json.Serialization.JsonSerializerContext jsonSerializerContext)
{
return (await global::System.Text.Json.JsonSerializer.DeserializeAsync(
jsonStream,
typeof(global::Ultravox.UltravoxV1GoogleVoice),
jsonSerializerContext).ConfigureAwait(false)) as global::Ultravox.UltravoxV1GoogleVoice;
}

/// <summary>
/// Deserializes a JSON stream using the provided JsonSerializerOptions.
/// </summary>
#if NET8_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
[global::System.Diagnostics.CodeAnalysis.RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")]
#endif
public static global::System.Threading.Tasks.ValueTask<global::Ultravox.UltravoxV1GoogleVoice?> FromJsonStreamAsync(
global::System.IO.Stream jsonStream,
global::System.Text.Json.JsonSerializerOptions? jsonSerializerOptions = null)
{
return global::System.Text.Json.JsonSerializer.DeserializeAsync<global::Ultravox.UltravoxV1GoogleVoice?>(
jsonStream,
jsonSerializerOptions);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

#nullable enable

namespace Ultravox
{
/// <summary>
/// Specification for a voice served by Google.<br/>
/// This implementation uses bidirectional streaming, so voices prior to Chirp3 are not supported.
/// </summary>
public sealed partial class UltravoxV1GoogleVoice
{
/// <summary>
/// The ID (name) of the voice in Google, e.g. "en-US-Chirp3-HD-Charon".
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("voiceId")]
public string? VoiceId { get; set; }

/// <summary>
/// The speaking rate. Must be between 0.25 and 2. Defaults to 1.<br/>
/// See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("speakingRate")]
public float? SpeakingRate { get; set; }

/// <summary>
/// Additional properties that are not explicitly defined in the schema
/// </summary>
[global::System.Text.Json.Serialization.JsonExtensionData]
public global::System.Collections.Generic.IDictionary<string, object> AdditionalProperties { get; set; } = new global::System.Collections.Generic.Dictionary<string, object>();

/// <summary>
/// Initializes a new instance of the <see cref="UltravoxV1GoogleVoice" /> class.
/// </summary>
/// <param name="voiceId">
/// The ID (name) of the voice in Google, e.g. "en-US-Chirp3-HD-Charon".
/// </param>
/// <param name="speakingRate">
/// The speaking rate. Must be between 0.25 and 2. Defaults to 1.<br/>
/// See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig
/// </param>
#if NET7_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
#endif
public UltravoxV1GoogleVoice(
string? voiceId,
float? speakingRate)
{
this.VoiceId = voiceId;
this.SpeakingRate = speakingRate;
}

/// <summary>
/// Initializes a new instance of the <see cref="UltravoxV1GoogleVoice" /> class.
/// </summary>
public UltravoxV1GoogleVoice()
{
}
}
}
23 changes: 23 additions & 0 deletions src/libs/Ultravox/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2611,6 +2611,10 @@ components:
allOf:
- $ref: '#/components/schemas/KeyPrefix'
description: The LMNT API key.
google:
allOf:
- $ref: '#/components/schemas/KeyPrefix'
description: The Google service account key.
Agent:
required:
- agentId
Expand Down Expand Up @@ -3696,6 +3700,10 @@ components:
type: string
description: "Your LMNT API key.\nhttps://app.lmnt.com/account#api-keys"
nullable: true
google:
type: string
description: "A service account JSON key for your Google Cloud project with the Text-to-Speech API enabled.\nhttps://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#before-you-begin\nhttps://cloud.google.com/iam/docs/keys-create-delete#creating"
nullable: true
PatchedVoice:
type: object
properties:
Expand Down Expand Up @@ -4754,6 +4762,10 @@ components:
allOf:
- $ref: '#/components/schemas/ultravox.v1.LmntVoice'
description: A voice served by LMNT.
google:
allOf:
- $ref: '#/components/schemas/ultravox.v1.GoogleVoice'
description: "A voice served by Google, using bidirectional streaming.\n (For non-streaming or output-only streaming, use generic.)"
generic:
Comment on lines +4765 to 4769
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Confirm runtime truly requires “bidirectional streaming” (Chirp3+) for Google.

The description is specific and time-sensitive. Please confirm the server implementation currently only supports bidi streaming voices and that non-Chirp voices fail predictably; otherwise soften the claim.


🌐 Web query:

Does Google Cloud Text-to-Speech streaming (StreamingAudioConfig) require “Chirp3” voices, and what are the supported speakingRate bounds for streaming?

💡 Result:

Short answer:

  • No — StreamingAudioConfig (streaming TTS) does not require Chirp3 voices; it works with the supported voices listed in the Voices page (Wavenet, Neural2, Chirp/Chirp3, Studio, Standard, etc.). [1][2]
  • The supported speakingRate bounds for streaming are 0.25 to 2.0 (values outside that range return an error; default is 1.0). [1]

Sources:
[1] Google Cloud Text‑to‑Speech StreamingAudioConfig doc (speakingRate range).
[2] Google Cloud Text‑to‑Speech supported voices list (shows available voice families including Chirp/Chirp3).


Clarify Google voice description in OpenAPI schema
Update the description to note that StreamingAudioConfig supports all streaming-compatible voice families (Wavenet, Neural2, Chirp3, Studio, Standard) rather than implying Chirp3-only.

File: src/libs/Ultravox/openapi.yaml Lines 4765-4769

-          description: "A voice served by Google, using bidirectional streaming.\n (For non-streaming or output-only streaming, use generic.)"
+          description: "A voice served by Google using bidirectional streaming; supports all streaming-compatible voice families (Wavenet, Neural2, Chirp3, Studio, Standard).\n (For non-streaming or output-only streaming, use generic.)"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
google:
allOf:
- $ref: '#/components/schemas/ultravox.v1.GoogleVoice'
description: "A voice served by Google, using bidirectional streaming.\n (For non-streaming or output-only streaming, use generic.)"
generic:
google:
allOf:
- $ref: '#/components/schemas/ultravox.v1.GoogleVoice'
description: "A voice served by Google using bidirectional streaming; supports all streaming-compatible voice families (Wavenet, Neural2, Chirp3, Studio, Standard).\n (For non-streaming or output-only streaming, use generic.)"
generic:
🤖 Prompt for AI Agents
In src/libs/Ultravox/openapi.yaml around lines 4765-4769, the description for
the "google" voice currently implies Chirp3-only streaming support; update that
description string to state that StreamingAudioConfig supports all
streaming-compatible Google voice families (Wavenet, Neural2, Chirp3, Studio,
Standard) for bidirectional streaming, and reword to avoid implying exclusivity
(keep existing note about non-streaming/output-only using generic).

allOf:
- $ref: '#/components/schemas/ultravox.v1.GenericVoice'
Expand Down Expand Up @@ -4839,6 +4851,17 @@ components:
type: string
description: "For JSON responses, the path to the field containing base64-encoded audio data. The data must\n be PCM audio, optionally with a WAV header."
description: "Specification for a voice served by some generic REST-based TTS API. The API must\n accept an application/json POST request (as defined below) and return either WAV\n audio, raw PCM audio, or application/json with a base64 encoded audio data field\n that itself corresponds to WAV or raw PCM audio.\n Note that this simple API implies a lack of either input streaming or audio timing\n information, so more specific voice types are preferable when available."
ultravox.v1.GoogleVoice:
type: object
properties:
voiceId:
type: string
description: 'The ID (name) of the voice in Google, e.g. "en-US-Chirp3-HD-Charon".'
speakingRate:
type: number
description: "The speaking rate. Must be between 0.25 and 2. Defaults to 1.\n See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig"
format: float
description: "Specification for a voice served by Google.\n This implementation uses bidirectional streaming, so voices prior to Chirp3 are not supported."
ultravox.v1.HeaderApiKeyRequirement:
Comment on lines +4854 to 4865
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Add validation bounds and a default for speakingRate; include an example voiceId.

Without min/max/default, clients can submit out-of-range values that will fail at runtime. This mirrors other provider schemas (e.g., LMNT speed 0.25–2, ElevenLabs speed defaults).

Proposed schema tweaks:

     ultravox.v1.GoogleVoice:
       type: object
       properties:
         voiceId:
           type: string
-          description: 'The ID (name) of the voice in Google, e.g. "en-US-Chirp3-HD-Charon".'
+          description: 'The ID (name) of the voice in Google.'
+          example: en-US-Chirp3-HD-Charon
         speakingRate:
           type: number
-          description: "The speaking rate. Must be between 0.25 and 2. Defaults to 1.
- See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig"
           format: float
+          minimum: 0.25
+          maximum: 2
+          default: 1
+          description: "The speaking rate.
+ See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig"
-      description: "Specification for a voice served by Google.
- This implementation uses bidirectional streaming, so voices prior to Chirp3 are not supported."
+      description: "Specification for a voice served by Google. Uses bidirectional streaming."

Also, please verify that the referenced Python type path is correct for the current client library and version.


🌐 Web query:

Is `google.cloud.texttospeech_v1.types.StreamingAudioConfig` the correct Python type path for Google Cloud TTS streaming configuration?

💡 Result:

Yes. The Python type is google.cloud.texttospeech_v1.types.StreamingAudioConfig. [1][2]

References:

  • Library reference for StreamingAudioConfig. [1]
  • Streaming quickstart / examples showing streaming config usage. [2]

Add validation bounds, default, and example to GoogleVoice schema

     ultravox.v1.GoogleVoice:
       type: object
       properties:
         voiceId:
-          description: 'The ID (name) of the voice in Google, e.g. "en-US-Chirp3-HD-Charon".'
+          description: 'The ID (name) of the voice in Google.'
+          example: en-US-Chirp3-HD-Charon
         speakingRate:
           type: number
           format: float
+          minimum: 0.25
+          maximum: 2
+          default: 1
           description: "The speaking rate.
 See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig"
-      description: "Specification for a voice served by Google.
- This implementation uses bidirectional streaming, so voices prior to Chirp3 are not supported."
+      description: "Specification for a voice served by Google. Uses bidirectional streaming."

Verified that google.cloud.texttospeech_v1.types.StreamingAudioConfig is the correct Python type path.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ultravox.v1.GoogleVoice:
type: object
properties:
voiceId:
type: string
description: 'The ID (name) of the voice in Google, e.g. "en-US-Chirp3-HD-Charon".'
speakingRate:
type: number
description: "The speaking rate. Must be between 0.25 and 2. Defaults to 1.\n See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig"
format: float
description: "Specification for a voice served by Google.\n This implementation uses bidirectional streaming, so voices prior to Chirp3 are not supported."
ultravox.v1.HeaderApiKeyRequirement:
ultravox.v1.GoogleVoice:
type: object
properties:
voiceId:
type: string
description: 'The ID (name) of the voice in Google.'
example: en-US-Chirp3-HD-Charon
speakingRate:
type: number
format: float
minimum: 0.25
maximum: 2
default: 1
description: "The speaking rate.
See https://cloud.google.com/python/docs/reference/texttospeech/latest/google.cloud.texttospeech_v1.types.StreamingAudioConfig"
description: "Specification for a voice served by Google. Uses bidirectional streaming."
ultravox.v1.HeaderApiKeyRequirement:
🤖 Prompt for AI Agents
In src/libs/Ultravox/openapi.yaml around lines 4854-4865, the
ultravox.v1.GoogleVoice schema needs explicit validation and examples: for
speakingRate add minimum: 0.25, maximum: 2, default: 1 and an example (e.g.
1.0); ensure format: float stays; for voiceId add an example (e.g.
"en-US-Chirp3-HD-Charon") and, if desired, a pattern or minLength to validate
non-empty strings; optionally add an overall example for the GoogleVoice object
to show both fields together.

type: object
properties:
Expand Down