Skip to content

Commit 828b361

Browse files
authored
support multi-lingual ASR models (#723)
## Summary Update live audio transcription samples to use the correct Foundry Local catalog alias for the multilingual Nemotron ASR model, and strip model-emitted language tags in the SDK so all consumers receive clean transcription text. ## Changes ### Samples (all 5 languages) - Updated the commented multilingual model alias from `Nemotron-3.5-ASR-Streaming-Multilingual-0.6b-onnx-int4` to `nvidia-nemotron-3.5-asr-streaming-multilingual-0.6b` to match the FL catalog naming convention (mirrors the HuggingFace repo name) - Affected files: - `samples/cs/live-audio-transcription/Program.cs` - `samples/js/live-audio-transcription/app.js` - `samples/python/live-audio-transcription/src/app.py` - `samples/cpp/live-audio-transcription/main.cpp` - `samples/rust/live-audio-transcription/src/main.rs` ### SDK (`sdk/cs/src/OpenAI/LiveAudioTypes.cs`) - Strip language identification tags (e.g. `<zh-CN>`, `<en-US>`) from transcription text in `LiveAudioTranscriptionResponse.FromJson()` - Multilingual Nemotron models emit these tags at segment boundaries as language identifiers — following industry convention (Whisper, Azure Speech, Google STT), these should be returned as metadata rather than inline text - All SDK consumers now receive clean text without needing client-side post-processing ## Testing Verified end-to-end with `nvidia-nemotron-3.5-asr-streaming-multilingual-0.6b` (INT4) model: - English speech → clean English transcription - Chinese speech (`zh-CN`) → clean Chinese transcription - Mixed language switching works correctly - Language tags stripped at the SDK layer before reaching consumers
1 parent 605dcb4 commit 828b361

6 files changed

Lines changed: 58 additions & 10 deletions

File tree

samples/cpp/live-audio-transcription/main.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,13 @@ int main(int argc, char* argv[]) {
126126
manager.DownloadAndRegisterEps(nullptr, isCancellationRequested);
127127

128128
auto& catalog = manager.GetCatalog();
129-
auto* model = catalog.GetModel("nemotron-speech-streaming-en-0.6b");
129+
// English-only:
130+
const char* modelAlias = "nemotron-speech-streaming-en-0.6b";
131+
// Multi-lingual (supports 30+ languages including auto-detect):
132+
// const char* modelAlias = "nvidia-nemotron-3.5-asr-streaming-multilingual-0.6b";
133+
auto* model = catalog.GetModel(modelAlias);
130134
if (!model) {
131-
throw std::runtime_error("Model \"nemotron-speech-streaming-en-0.6b\" not found in catalog");
135+
throw std::runtime_error(std::string("Model \"") + modelAlias + "\" not found in catalog");
132136
}
133137

134138
std::cout << "Downloading model (if needed)..." << std::endl;
@@ -151,7 +155,11 @@ int main(int argc, char* argv[]) {
151155
session->Settings().sample_rate = 16000;
152156
session->Settings().channels = 1;
153157
session->Settings().bits_per_sample = 16;
154-
session->Settings().language = "en";
158+
session->Settings().language = "en"; // English (default)
159+
// Multi-lingual examples:
160+
// session->Settings().language = "de"; // German
161+
// session->Settings().language = "zh-CN"; // Chinese (Simplified)
162+
// session->Settings().language = "auto"; // Auto-detect language
155163
session->Start();
156164
std::cout << "Session started" << std::endl;
157165

samples/cs/live-audio-transcription/Program.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@
2424

2525
var catalog = await mgr.GetCatalogAsync();
2626

27-
var model = await catalog.GetModelAsync("nemotron-speech-streaming-en-0.6b") ?? throw new Exception("Model \"nemotron-speech-streaming-en-0.6b\" not found in catalog");
27+
// English-only:
28+
var modelAlias = "nemotron-speech-streaming-en-0.6b";
29+
// Multi-lingual (supports 30+ languages including auto-detect):
30+
// var modelAlias = "nvidia-nemotron-3.5-asr-streaming-multilingual-0.6b";
31+
32+
var model = await catalog.GetModelAsync(modelAlias) ?? throw new Exception($"Model \"{modelAlias}\" not found in catalog");
2833

2934
await model.DownloadAsync(progress =>
3035
{
@@ -43,7 +48,11 @@ await model.DownloadAsync(progress =>
4348
var session = audioClient.CreateLiveTranscriptionSession();
4449
session.Settings.SampleRate = 16000; // Default is 16000; shown here to match the NAudio WaveFormat below
4550
session.Settings.Channels = 1;
46-
session.Settings.Language = "en";
51+
session.Settings.Language = "en"; // English (default)
52+
// Multi-lingual examples:
53+
// session.Settings.Language = "de"; // German
54+
// session.Settings.Language = "zh-CN"; // Chinese (Simplified)
55+
// session.Settings.Language = "auto"; // Auto-detect language
4756

4857
await session.StartAsync();
4958
Console.WriteLine(" Session started");

samples/js/live-audio-transcription/app.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ const manager = FoundryLocalManager.create({
2121
console.log('✓ SDK initialized');
2222

2323
// Get and load the nemotron model
24+
// English-only:
2425
const modelAlias = 'nemotron-speech-streaming-en-0.6b';
26+
// Multi-lingual (supports 30+ languages including auto-detect):
27+
// const modelAlias = 'nvidia-nemotron-3.5-asr-streaming-multilingual-0.6b';
2528
let model = await manager.catalog.getModel(modelAlias);
2629
if (!model) {
2730
console.error(`ERROR: Model "${modelAlias}" not found in catalog.`);
@@ -46,7 +49,11 @@ const session = audioClient.createLiveTranscriptionSession();
4649
session.settings.sampleRate = 16000; // Default is 16000; shown here for clarity
4750
session.settings.channels = 1;
4851
session.settings.bitsPerSample = 16;
49-
session.settings.language = 'en';
52+
session.settings.language = 'en'; // English (default)
53+
// Multi-lingual examples:
54+
// session.settings.language = 'de'; // German
55+
// session.settings.language = 'zh-CN'; // Chinese (Simplified)
56+
// session.settings.language = 'auto'; // Auto-detect language
5057

5158
console.log('Starting streaming session...');
5259
await session.start();

samples/python/live-audio-transcription/src/app.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@
2929

3030
manager.download_and_register_eps()
3131

32-
model = manager.catalog.get_model("nemotron-speech-streaming-en-0.6b")
32+
# English-only:
33+
model_alias = "nemotron-speech-streaming-en-0.6b"
34+
# Multi-lingual (supports 30+ languages including auto-detect):
35+
# model_alias = "nvidia-nemotron-3.5-asr-streaming-multilingual-0.6b"
36+
model = manager.catalog.get_model(model_alias)
3337
if model is None:
34-
raise RuntimeError('Model "nemotron-speech-streaming-en-0.6b" not found in catalog')
38+
raise RuntimeError(f'Model "{model_alias}" not found in catalog')
3539

3640
model.download(
3741
lambda progress: print(f"\rDownloading model: {progress:.2f}%", end="", flush=True)
@@ -45,7 +49,11 @@
4549
session = audio_client.create_live_transcription_session()
4650
session.settings.sample_rate = 16000
4751
session.settings.channels = 1
48-
session.settings.language = "en"
52+
session.settings.language = "en" # English (default)
53+
# Multi-lingual examples:
54+
# session.settings.language = "de" # German
55+
# session.settings.language = "zh-CN" # Chinese (Simplified)
56+
# session.settings.language = "auto" # Auto-detect language
4957

5058
session.start()
5159
print("✓ Session started")

samples/rust/live-audio-transcription/src/main.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
1515
use foundry_local_sdk::{FoundryLocalConfig, FoundryLocalManager, LiveAudioTranscriptionSession};
1616
use tokio_stream::StreamExt;
1717

18+
// English-only:
1819
const ALIAS: &str = "nemotron-speech-streaming-en-0.6b";
20+
// Multi-lingual (supports 30+ languages including auto-detect):
21+
// const ALIAS: &str = "nvidia-nemotron-3.5-asr-streaming-multilingual-0.6b";
1922

2023
// Global flag for Ctrl+C graceful shutdown (mirrors JS process.on('SIGINT'))
2124
static RUNNING: AtomicBool = AtomicBool::new(true);
@@ -57,7 +60,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
5760
println!("✓ Model loaded\n");
5861

5962
let audio_client = model.create_audio_client();
60-
let session = Arc::new(audio_client.create_live_transcription_session());
63+
let mut session = audio_client.create_live_transcription_session();
64+
session.settings.language = Some("en".into()); // English (default)
65+
// session.settings.language = Some("de".into()); // German
66+
// session.settings.language = Some("zh-CN".into()); // Chinese (Simplified)
67+
// session.settings.language = Some("auto".into()); // Auto-detect language
68+
let session = Arc::new(session);
6169
session.start(None).await?;
6270
println!("✓ Session started\n");
6371

sdk/cs/src/OpenAI/LiveAudioTypes.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ public class LiveAudioTranscriptionResponse : ConversationItem
3232
[JsonPropertyName("end_time")]
3333
public double? EndTime { get; init; }
3434

35+
/// <summary>BCP-47 language code detected by the model (e.g. "zh-CN", "en-US"), or null if not detected.</summary>
36+
[JsonPropertyName("language")]
37+
public string? Language { get; init; }
38+
3539
internal static LiveAudioTranscriptionResponse FromJson(string json)
3640
{
3741
var raw = JsonSerializer.Deserialize(json,
@@ -43,6 +47,7 @@ internal static LiveAudioTranscriptionResponse FromJson(string json)
4347
IsFinal = raw.IsFinal,
4448
StartTime = raw.StartTime,
4549
EndTime = raw.EndTime,
50+
Language = raw.Language,
4651
Content =
4752
[
4853
new ContentPart
@@ -72,6 +77,9 @@ internal record LiveAudioTranscriptionRaw
7277

7378
[JsonPropertyName("end_time")]
7479
public double? EndTime { get; init; }
80+
81+
[JsonPropertyName("language")]
82+
public string? Language { get; init; }
7583
}
7684

7785
internal record CoreErrorResponse

0 commit comments

Comments
 (0)