Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
4e0bdb6
Added probabilities to OnlineRecognizerResult
Dokotela Aug 24, 2025
1e5111e
maybe if I spell it right and in the right place
Dokotela Aug 24, 2025
b188759
flutter updates
Dokotela Sep 23, 2025
77dde1f
core probability files
Dokotela Sep 23, 2025
2e8033b
whisper probabilities
Dokotela Sep 23, 2025
2dc62a4
canary confidence scores
Dokotela Sep 23, 2025
0ad50a9
moonshine confidence scores
Dokotela Sep 23, 2025
fd13598
Merge branch 'master' of https://github.com/Dokotela/sherpa-onnx
Dokotela Sep 23, 2025
49f1919
streaming nemo confidences
Dokotela Sep 25, 2025
634cfd8
Merge branch 'master' of https://github.com/k2-fsa/sherpa-onnx
Dokotela Sep 25, 2025
cabd408
Removed debug statements
Dokotela Sep 25, 2025
06c97ae
Matching original formatting
Dokotela Sep 25, 2025
14ffa69
Renamed probability variable, removed word-level probability
Dokotela Sep 25, 2025
2620453
token_probs -> token_log_probs
Dokotela Sep 25, 2025
ae4b752
Adding full vocab log probs
Dokotela Oct 9, 2025
2a674d8
Merge branch 'k2-fsa:master' into master
Dokotela Oct 9, 2025
a4ac5f8
Merge branch 'master' of https://github.com/Dokotela/sherpa-onnx
Dokotela Oct 9, 2025
abe6179
Streaming does seem to have probabilities now
Dokotela Oct 10, 2025
44a8571
don't remember if I needed this
Dokotela Dec 1, 2025
1a85fd4
Merge upstream/master: Sync with k2-fsa/sherpa-onnx while preserving …
Dokotela Dec 14, 2025
51c97d1
Making as few adjustments as I can
Dokotela Dec 14, 2025
fbc1f66
Straightforward fixes to Gemini Code's PR Comments
Dokotela Dec 14, 2025
ce7f975
Should be cleaned now
Dokotela Dec 14, 2025
ff6bd92
Add guard for invalid temperature_scale in NeMo decoder
Dokotela Dec 14, 2025
d4e3e9c
Fix vocab_log_probs alignment: use idx directly instead of separate c…
Dokotela Dec 14, 2025
f895643
Two more fixes
Dokotela Dec 14, 2025
c789d10
Optimize decoders and fix alignment per CodeRabbit review
Dokotela Dec 15, 2025
e10e710
Added imports, cleanup unused includes, clarified comments, moved vec…
Dokotela Dec 15, 2025
7d52885
Fix NeMo decoder: copy logits before modifying (issue on MacOS)
Dokotela Dec 15, 2025
70e305c
Added a comment clarifying that vocab_log_probs includes the blank pe…
Dokotela Dec 15, 2025
7aabaf9
Code rabbit is picky
Dokotela Dec 15, 2025
bc29883
unclear if this will work or not
Dokotela Dec 16, 2025
cb3434b
reverting back to the correct url
Dokotela Dec 16, 2025
c6ad516
trigger ci
Dokotela Dec 16, 2025
2cdb186
Merge branch 'master' into master
Dokotela Dec 27, 2025
53fef2f
Merge branch 'master' into master
Dokotela Jan 7, 2026
9233160
Fix CodeRabbit review issues: JSON serialization, type conversion, an…
Dokotela Jan 11, 2026
e818e25
Merge branch 'master' of https://github.com/Dokotela/sherpa-onnx
Dokotela Jan 11, 2026
83ba9ff
Apply CodeRabbit nitpick suggestions for consistency
Dokotela Jan 12, 2026
80b6f80
Fix struct redefinition error in offline-whisper-model-config.h
Dokotela Jan 12, 2026
67970fb
Add MedASR CTC model support to Flutter bindings
Dokotela Jan 12, 2026
2316c5a
Fix medasr-ctc example to use local sherpa_onnx package
Dokotela Jan 12, 2026
f30966f
Revert medasr example to use published sherpa_onnx package
Dokotela Jan 12, 2026
f034396
Merge upstream/master (v1.12.21)
Dokotela Jan 12, 2026
6f35262
Fix TODO comment to reference Vocabulary Log Probabilities API
Dokotela Jan 12, 2026
ce02979
Merge upstream/master: sync with latest changes (v1.12.23)
Dokotela Jan 22, 2026
b0d37fe
Fix merge conflicts in offline_recognizer.dart
Dokotela Jan 22, 2026
724ee36
Merge upstream/master: sync with k2-fsa/sherpa-onnx v1.12.29
Dokotela Mar 13, 2026
06c2c17
Add per-token log probabilities to CTC greedy search decoder
Dokotela Mar 13, 2026
496f0c4
Fix native memory leak and DRY up JSON parsing in OfflineRecognizer
Dokotela Mar 13, 2026
882a858
Remove formatting noise from diff to keep PR reviewable
Dokotela Mar 13, 2026
c86bab9
Fix bugs in vocab_log_probs propagation and numerical precision
Dokotela Mar 13, 2026
402379b
Revert unrelated merge artifacts to sync with upstream
Dokotela Mar 13, 2026
3052e77
Remove formatting-only changes to keep PR diff clean
Dokotela Mar 13, 2026
22ead23
Fix three bugs in vocab_log_probs feature
Dokotela Mar 13, 2026
2bcdf7a
Fix minor issues in vocab_log_probs and bindings
Dokotela Mar 13, 2026
caf7d0e
Fix remaining merge artifacts missed in initial cleanup
Dokotela Mar 13, 2026
98e0a3e
Remove stray blank line in canary RunEncoder
Dokotela Mar 13, 2026
0466c61
Merge remote-tracking branch 'upstream/master'
Dokotela Mar 13, 2026
95c902b
Use fromJson in online getResult for consistency and null safety
Dokotela Mar 14, 2026
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
11 changes: 10 additions & 1 deletion flutter/sherpa_onnx/lib/src/offline_recognizer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ class OfflineRecognizerResult {
OfflineRecognizerResult(
{required this.text,
required this.tokens,
required this.tokenLogProbs,
required this.timestamps,
required this.lang,
required this.emotion,
Expand All @@ -606,6 +607,10 @@ class OfflineRecognizerResult {
return OfflineRecognizerResult(
text: json['text'] as String? ?? '',
tokens: (json['tokens'] as List?)?.map((e) => e as String).toList() ?? [],
tokenLogProbs: (json['token_log_probs'] as List?)
?.map((e) => (e as num).toDouble())
.toList() ??
[],
timestamps: (json['timestamps'] as List?)
?.map((e) => (e as num).toDouble())
.toList() ??
Expand All @@ -618,12 +623,13 @@ class OfflineRecognizerResult {

@override
String toString() {
return 'OfflineRecognizerResult(text: $text, tokens: $tokens, timestamps: $timestamps, lang: $lang, emotion: $emotion, event: $event)';
return 'OfflineRecognizerResult(text: $text, tokens: $tokens, tokenLogProbs: $tokenLogProbs, timestamps: $timestamps, lang: $lang, emotion: $emotion, event: $event)';
}

Map<String, dynamic> toJson() => {
'text': text,
'tokens': tokens,
'tokenLogProbs': tokenLogProbs,
'timestamps': timestamps,
'lang': lang,
'emotion': emotion,
Expand All @@ -632,6 +638,7 @@ class OfflineRecognizerResult {

final String text;
final List<String> tokens;
final List<double> tokenLogProbs;
final List<double> timestamps;
final String lang;
final String emotion;
Expand Down Expand Up @@ -841,6 +848,7 @@ class OfflineRecognizer {
return OfflineRecognizerResult(
text: '',
tokens: [],
tokenLogProbs: [],
timestamps: [],
lang: '',
emotion: '',
Expand All @@ -854,6 +862,7 @@ class OfflineRecognizer {
return OfflineRecognizerResult(
text: parsedJson['text'],
tokens: List<String>.from(parsedJson['tokens']),
tokenLogProbs: List<double>.from(parsedJson['token_log_probs'] ?? []),
timestamps: List<double>.from(parsedJson['timestamps']),
lang: parsedJson['lang'],
emotion: parsedJson['emotion'],
Expand Down
35 changes: 35 additions & 0 deletions flutter/sherpa_onnx/lib/src/offline_stream.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,40 @@ class OfflineStream {
calloc.free(p);
}

Map<String, List<double>>? getVocabLogProbs() {
final getFunc = SherpaOnnxBindings.getOfflineStreamVocabLogProbs;
final destroyFunc = SherpaOnnxBindings.destroyVocabLogProbs;

if (getFunc == null || destroyFunc == null) {
return null;
}

final vocabPtr = getFunc(ptr);
if (vocabPtr == nullptr) {
return null;
}

final vocabLogProbs = vocabPtr.ref;
final numTokens = vocabLogProbs.numTokens;
final vocabSize = vocabLogProbs.vocabSize;

final Map<String, List<double>> result = {};

for (int tokenIdx = 0; tokenIdx < numTokens; tokenIdx++) {
final List<double> tokenProbs = [];

for (int vocabIdx = 0; vocabIdx < vocabSize; vocabIdx++) {
final index = tokenIdx * vocabSize + vocabIdx;
final logProb = vocabLogProbs.logProbs[index];
tokenProbs.add(logProb);
}

result['token_$tokenIdx'] = tokenProbs;
}

destroyFunc(vocabPtr);
return result;
}

Pointer<SherpaOnnxOfflineStream> ptr;
}
14 changes: 11 additions & 3 deletions flutter/sherpa_onnx/lib/src/online_recognizer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ class OnlineRecognizerConfig {

class OnlineRecognizerResult {
OnlineRecognizerResult(
{required this.text, required this.tokens, required this.timestamps});
{required this.text, required this.tokens, required this.timestamps, this.ysProbs = const <double>[]});

factory OnlineRecognizerResult.fromJson(Map<String, dynamic> json) {
return OnlineRecognizerResult(
Expand All @@ -336,23 +336,28 @@ class OnlineRecognizerResult {
timestamps: (json['timestamps'] as List)
.map<double>((e) => (e as num).toDouble())
.toList(),
ysProbs: (json['ys_probs'] as List?)
?.map<double>((e) => (e as num).toDouble())
.toList() ?? const <double>[],
);
}

@override
String toString() {
return 'OnlineRecognizerResult(text: $text, tokens: $tokens, timestamps: $timestamps)';
return 'OnlineRecognizerResult(text: $text, tokens: $tokens, timestamps: $timestamps, ysProbs: $ysProbs)';
}

Map<String, dynamic> toJson() => {
'text': text,
'tokens': tokens,
'timestamps': timestamps,
'ys_probs': ysProbs,
};

final String text;
final List<String> tokens;
final List<double> timestamps;
final List<double> ysProbs;
}

class OnlineRecognizer {
Expand Down Expand Up @@ -499,7 +504,10 @@ class OnlineRecognizer {
return OnlineRecognizerResult(
text: parsedJson['text'],
tokens: List<String>.from(parsedJson['tokens']),
timestamps: List<double>.from(parsedJson['timestamps']));
timestamps: List<double>.from(parsedJson['timestamps']),
ysProbs: (parsedJson['ys_probs'] as List<dynamic>?)
?.map<double>((e) => (e as num).toDouble())
.toList() ?? <double>[]);
}

void reset(OnlineStream stream) {
Expand Down
35 changes: 35 additions & 0 deletions flutter/sherpa_onnx/lib/src/online_stream.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,40 @@ class OnlineStream {
SherpaOnnxBindings.onlineStreamInputFinished?.call(ptr);
}

Map<String, List<double>>? getVocabLogProbs() {
final getFunc = SherpaOnnxBindings.getOnlineStreamVocabLogProbs;
final destroyFunc = SherpaOnnxBindings.destroyVocabLogProbs;

if (getFunc == null || destroyFunc == null) {
return null;
}

final vocabPtr = getFunc(this.ptr);
if (vocabPtr == nullptr) {
return null;
}

final vocabLogProbs = vocabPtr.ref;
final numTokens = vocabLogProbs.numTokens;
final vocabSize = vocabLogProbs.vocabSize;

final Map<String, List<double>> result = {};

for (int tokenIdx = 0; tokenIdx < numTokens; tokenIdx++) {
final List<double> tokenProbs = [];

for (int vocabIdx = 0; vocabIdx < vocabSize; vocabIdx++) {
final index = tokenIdx * vocabSize + vocabIdx;
final logProb = vocabLogProbs.logProbs[index];
tokenProbs.add(logProb);
}

result['token_$tokenIdx'] = tokenProbs;
}

destroyFunc(vocabPtr);
return result;
}

Pointer<SherpaOnnxOnlineStream> ptr;
}
49 changes: 49 additions & 0 deletions flutter/sherpa_onnx/lib/src/sherpa_onnx_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,17 @@ final class SherpaOnnxSpokenLanguageIdentificationResult extends Struct {
external Pointer<Utf8> lang;
}

final class SherpaOnnxVocabLogProbs extends Struct {
// Flattened 2D array
external Pointer<Float> logProbs;

@Int32()
external int numTokens;

@Int32()
external int vocabSize;
}

final class SherpaOnnxSpokenLanguageIdentification extends Opaque {}

final class SherpaOnnxOfflineSpeechDenoiser extends Opaque {}
Expand Down Expand Up @@ -1419,6 +1430,20 @@ typedef SherpaOnnxGetGitSha1 = SherpaOnnxGetGitSha1Native;
typedef SherpaOnnxGetGitDateNative = Pointer<Utf8> Function();
typedef SherpaOnnxGetGitDate = SherpaOnnxGetGitDateNative;

typedef SherpaOnnxOnlineStreamGetVocabLogProbsNative
= Pointer<SherpaOnnxVocabLogProbs> Function(
Pointer<SherpaOnnxOnlineStream> stream);

typedef SherpaOnnxOfflineStreamGetVocabLogProbsNative
= Pointer<SherpaOnnxVocabLogProbs> Function(
Pointer<SherpaOnnxOfflineStream> stream);

typedef SherpaOnnxDestroyVocabLogProbsNative = Void Function(
Pointer<SherpaOnnxVocabLogProbs> logProbs);

typedef SherpaOnnxDestroyVocabLogProbsDart = void Function(
Pointer<SherpaOnnxVocabLogProbs>);

class SherpaOnnxBindings {
static SherpaOnnxCreateOfflineSpeechDenoiser?
sherpaOnnxCreateOfflineSpeechDenoiser;
Expand Down Expand Up @@ -1644,6 +1669,12 @@ class SherpaOnnxBindings {
static SherpaOnnxGetGitSha1? getGitSha1;
static SherpaOnnxGetGitDate? getGitDate;

static SherpaOnnxOnlineStreamGetVocabLogProbsNative?
getOnlineStreamVocabLogProbs;
static SherpaOnnxOfflineStreamGetVocabLogProbsNative?
getOfflineStreamVocabLogProbs;
static SherpaOnnxDestroyVocabLogProbsDart? destroyVocabLogProbs;

static void init(DynamicLibrary dynamicLibrary) {
sherpaOnnxCreateOfflineSpeechDenoiser ??= dynamicLibrary
.lookup<NativeFunction<SherpaOnnxCreateOfflineSpeechDenoiserNative>>(
Expand Down Expand Up @@ -2290,5 +2321,23 @@ class SherpaOnnxBindings {
.lookup<NativeFunction<SherpaOnnxGetGitDateNative>>(
'SherpaOnnxGetGitDate')
.asFunction();

getOnlineStreamVocabLogProbs = dynamicLibrary.lookupFunction<
SherpaOnnxOnlineStreamGetVocabLogProbsNative,
SherpaOnnxOnlineStreamGetVocabLogProbsNative>(
'SherpaOnnxOnlineStreamGetVocabLogProbs',
);

getOfflineStreamVocabLogProbs = dynamicLibrary.lookupFunction<
SherpaOnnxOfflineStreamGetVocabLogProbsNative,
SherpaOnnxOfflineStreamGetVocabLogProbsNative>(
'SherpaOnnxOfflineStreamGetVocabLogProbs',
);

destroyVocabLogProbs = dynamicLibrary.lookupFunction<
SherpaOnnxDestroyVocabLogProbsNative,
SherpaOnnxDestroyVocabLogProbsDart>(
'SherpaOnnxDestroyVocabLogProbs',
);
}
}
1 change: 1 addition & 0 deletions flutter/sherpa_onnx/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies:
# path: ../sherpa_onnx_macos

sherpa_onnx_linux: ^1.12.19
# Use local path for development, uncomment below for local development
# sherpa_onnx_linux:
# path: ../sherpa_onnx_linux

Expand Down
59 changes: 59 additions & 0 deletions sherpa-onnx/c-api/c-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,65 @@ const char *SherpaOnnxGetOfflineStreamResultAsJson(

void SherpaOnnxDestroyOfflineStreamResultJson(const char *s) { delete[] s; }

const struct SherpaOnnxVocabLogProbs *SherpaOnnxOnlineStreamGetVocabLogProbs(
const SherpaOnnxOnlineStream *stream) {
const auto &result = stream->impl->GetResult();

if (result.vocab_log_probs.empty()) {
return nullptr;
}

auto vocab_probs = new SherpaOnnxVocabLogProbs;
vocab_probs->num_tokens = result.vocab_log_probs.size();
vocab_probs->vocab_size = result.vocab_log_probs[0].size();

// Flatten the 2D vector into a 1D array
float *flat_probs =
new float[vocab_probs->num_tokens * vocab_probs->vocab_size];
for (int32_t i = 0; i < vocab_probs->num_tokens; ++i) {
std::copy(result.vocab_log_probs[i].begin(),
result.vocab_log_probs[i].end(),
flat_probs + i * vocab_probs->vocab_size);
}
vocab_probs->log_probs = flat_probs;

return vocab_probs;
}

const struct SherpaOnnxVocabLogProbs *SherpaOnnxOfflineStreamGetVocabLogProbs(
const SherpaOnnxOfflineStream *stream) {
const sherpa_onnx::OfflineRecognitionResult &result =
stream->impl->GetResult();

if (result.vocab_log_probs.empty()) {
return nullptr;
}

auto vocab_probs = new SherpaOnnxVocabLogProbs;
vocab_probs->num_tokens = result.vocab_log_probs.size();
vocab_probs->vocab_size = result.vocab_log_probs[0].size();

// Flatten the 2D vector into a 1D array
float *flat_probs =
new float[vocab_probs->num_tokens * vocab_probs->vocab_size];
for (int32_t i = 0; i < vocab_probs->num_tokens; ++i) {
std::copy(result.vocab_log_probs[i].begin(),
result.vocab_log_probs[i].end(),
flat_probs + i * vocab_probs->vocab_size);
}
vocab_probs->log_probs = flat_probs;

return vocab_probs;
}

void SherpaOnnxDestroyVocabLogProbs(
const struct SherpaOnnxVocabLogProbs *log_probs) {
if (log_probs) {
delete[] log_probs->log_probs;
delete log_probs;
}
}

// ============================================================
// For Keyword Spot
// ============================================================
Expand Down
15 changes: 15 additions & 0 deletions sherpa-onnx/c-api/c-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,21 @@ SHERPA_ONNX_API typedef struct SherpaOnnxOfflineRecognizerResult {
float *ys_log_probs;
} SherpaOnnxOfflineRecognizerResult;

SHERPA_ONNX_API typedef struct SherpaOnnxVocabLogProbs {
const float *log_probs; // Flattened 2D array [num_tokens][vocab_size]
int32_t num_tokens;
int32_t vocab_size;
} SherpaOnnxVocabLogProbs;

SHERPA_ONNX_API const SherpaOnnxVocabLogProbs *
SherpaOnnxOnlineStreamGetVocabLogProbs(const SherpaOnnxOnlineStream *stream);

SHERPA_ONNX_API const SherpaOnnxVocabLogProbs *
SherpaOnnxOfflineStreamGetVocabLogProbs(const SherpaOnnxOfflineStream *stream);

SHERPA_ONNX_API void SherpaOnnxDestroyVocabLogProbs(
const SherpaOnnxVocabLogProbs *log_probs);

/// Get the result of the offline stream.
///
/// We assume you have called SherpaOnnxDecodeOfflineStream() or
Expand Down
5 changes: 5 additions & 0 deletions sherpa-onnx/csrc/offline-ctc-decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ struct OfflineCtcDecoderResult {
///
/// tokens.size() == timestamps.size()
std::vector<int32_t> timestamps;

/// Token-level log probabilities (confidence scores).
/// May be empty if not provided by the decoder.
/// If populated, token_log_probs.size() == tokens.size()
std::vector<float> token_log_probs;
};

class OfflineCtcDecoder {
Expand Down
3 changes: 3 additions & 0 deletions sherpa-onnx/csrc/offline-moonshine-decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace sherpa_onnx {
struct OfflineMoonshineDecoderResult {
/// The decoded token IDs
std::vector<int32_t> tokens;
/// Token-level log probabilities (confidence scores)
std::vector<float> token_log_probs;
std::vector<std::vector<float>> vocab_log_probs;
};

class OfflineMoonshineDecoder {
Expand Down
Loading
Loading