Skip to content

Commit 99206ad

Browse files
authored
Add Java and Kotlin API for Cohere Transcribe (#3461)
This pull request introduces support for the Cohere Transcribe model across the Java and Kotlin APIs. Key changes include the addition of the OfflineCohereTranscribeModelConfig class, updated JNI bindings to handle the new configuration, and new example scripts and source files for both languages.
1 parent d4465bc commit 99206ad

13 files changed

Lines changed: 332 additions & 10 deletions

File tree

.github/workflows/jni.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- master
7+
- jni
78
- kotlin
89
paths:
910
- '.github/workflows/jni.yaml'

.github/workflows/run-java-test.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- master
7+
- jni
78
- java
89
paths:
910
- '.github/workflows/run-java-test.yaml'
@@ -109,6 +110,13 @@ jobs:
109110
cd ./java-api-examples
110111
./run-version-test.sh
111112
113+
- name: Run java test (Cohere Transcribe)
114+
shell: bash
115+
run: |
116+
cd ./java-api-examples
117+
./run-non-streaming-decode-file-cohere-transcribe.sh
118+
rm -rf sherpa-onnx-cohere-transcribe-*
119+
112120
- name: Run java test (Qwen3 ASR)
113121
if: matrix.os != 'ubuntu-latest'
114122
shell: bash
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2026 Xiaomi Corporation
2+
3+
// This file shows how to use an offline Cohere Transcribe model
4+
// to decode files.
5+
import com.k2fsa.sherpa.onnx.*;
6+
7+
public class NonStreamingDecodeFileCohereTranscribe {
8+
public static void main(String[] args) {
9+
String modelDir = "./sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01";
10+
String encoder = modelDir + "/encoder.int8.onnx";
11+
String decoder = modelDir + "/decoder.int8.onnx";
12+
String tokens = modelDir + "/tokens.txt";
13+
14+
String waveFilename = modelDir + "/test_wavs/en.wav";
15+
16+
WaveReader reader = new WaveReader(waveFilename);
17+
18+
OfflineCohereTranscribeModelConfig cohereTranscribe =
19+
OfflineCohereTranscribeModelConfig.builder()
20+
.setEncoder(encoder)
21+
.setDecoder(decoder)
22+
.setUsePunct(true)
23+
.setUseItn(true)
24+
.build();
25+
26+
OfflineModelConfig modelConfig =
27+
OfflineModelConfig.builder()
28+
.setCohereTranscribe(cohereTranscribe)
29+
.setTokens(tokens)
30+
.setNumThreads(2)
31+
.setDebug(true)
32+
.build();
33+
34+
OfflineRecognizerConfig config =
35+
OfflineRecognizerConfig.builder()
36+
.setOfflineModelConfig(modelConfig)
37+
.setDecodingMethod("greedy_search")
38+
.build();
39+
40+
OfflineRecognizer recognizer = new OfflineRecognizer(config);
41+
OfflineStream stream = recognizer.createStream();
42+
stream.setOption("language", "en");
43+
stream.acceptWaveform(reader.getSamples(), reader.getSampleRate());
44+
45+
long start = System.currentTimeMillis();
46+
recognizer.decode(stream);
47+
long stop = System.currentTimeMillis();
48+
49+
String text = recognizer.getResult(stream).getText();
50+
51+
float timeElapsedSeconds = (stop - start) / 1000.0f;
52+
float audioDuration = reader.getSamples().length / (float) reader.getSampleRate();
53+
float realTimeFactor = timeElapsedSeconds / audioDuration;
54+
55+
System.out.printf("filename:%s\nresult:%s\n", waveFilename, text);
56+
System.out.printf("-- elapsed : %.3f seconds\n", timeElapsedSeconds);
57+
System.out.printf("-- audio duration: %.3f seconds\n", audioDuration);
58+
System.out.printf("-- real-time factor (RTF): %.3f\n", realTimeFactor);
59+
60+
stream.release();
61+
recognizer.release();
62+
}
63+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env bash
2+
3+
set -ex
4+
5+
if [[ ! -f ../build/lib/libsherpa-onnx-jni.dylib && ! -f ../build/lib/libsherpa-onnx-jni.so ]]; then
6+
mkdir -p ../build
7+
pushd ../build
8+
cmake \
9+
-DSHERPA_ONNX_ENABLE_PYTHON=OFF \
10+
-DSHERPA_ONNX_ENABLE_TESTS=OFF \
11+
-DSHERPA_ONNX_ENABLE_CHECK=OFF \
12+
-DBUILD_SHARED_LIBS=ON \
13+
-DSHERPA_ONNX_ENABLE_PORTAUDIO=OFF \
14+
-DSHERPA_ONNX_ENABLE_JNI=ON \
15+
..
16+
17+
make -j4
18+
ls -lh lib
19+
popd
20+
fi
21+
22+
if [ ! -f ../sherpa-onnx/java-api/build/sherpa-onnx.jar ]; then
23+
pushd ../sherpa-onnx/java-api
24+
make
25+
popd
26+
fi
27+
28+
if [ ! -f ./sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01/encoder.int8.onnx ]; then
29+
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01.tar.bz2
30+
tar xvf sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01.tar.bz2
31+
rm sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01.tar.bz2
32+
ls -lh sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01
33+
fi
34+
35+
java \
36+
-Djava.library.path=$PWD/../build/lib \
37+
-cp ../sherpa-onnx/java-api/build/sherpa-onnx.jar \
38+
NonStreamingDecodeFileCohereTranscribe.java

kotlin-api-examples/run.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,28 @@ function testOfflineQwen3Asr() {
737737
java -Djava.library.path=../build/lib -jar $out_filename
738738
}
739739

740+
function testOfflineCohereTranscribe() {
741+
if [ ! -f ./sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01/encoder.int8.onnx ]; then
742+
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01.tar.bz2
743+
tar xvf sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01.tar.bz2
744+
rm sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01.tar.bz2
745+
fi
746+
747+
out_filename=test_offline_cohere_transcribe.jar
748+
kotlinc-jvm -include-runtime -d $out_filename \
749+
test_offline_cohere_transcribe.kt \
750+
FeatureConfig.kt \
751+
QnnConfig.kt \
752+
HomophoneReplacerConfig.kt \
753+
OfflineRecognizer.kt \
754+
OfflineStream.kt \
755+
WaveReader.kt \
756+
faked-asset-manager.kt
757+
758+
ls -lh $out_filename
759+
java -Djava.library.path=../build/lib -jar $out_filename
760+
}
761+
740762
function testOfflineWenetCtc() {
741763
if [ ! -f sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx ]; then
742764
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2
@@ -760,6 +782,7 @@ function testOfflineWenetCtc() {
760782
}
761783

762784
testVersion
785+
testOfflineCohereTranscribe
763786
testOfflineQwen3Asr
764787
testOfflineMoonshineAsrV2
765788
testOfflineFireRedAsrCtc
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.k2fsa.sherpa.onnx
2+
3+
fun main() {
4+
val recognizer = createOfflineRecognizer()
5+
val waveFilename = "./sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01/test_wavs/en.wav"
6+
7+
val waveData = WaveReader.readWaveFromFile(
8+
filename = waveFilename,
9+
)
10+
11+
val stream = recognizer.createStream()
12+
stream.setOption("language", "en")
13+
stream.acceptWaveform(waveData.samples, sampleRate=waveData.sampleRate)
14+
15+
val start = System.currentTimeMillis()
16+
recognizer.decode(stream)
17+
val stop = System.currentTimeMillis()
18+
19+
val result = recognizer.getResult(stream)
20+
println(result)
21+
22+
val timeElapsedSeconds = (stop - start) / 1000.0f
23+
val audioDuration = waveData.samples.size / waveData.sampleRate.toFloat()
24+
val realTimeFactor = timeElapsedSeconds / audioDuration
25+
26+
println(String.format("-- elapsed : %.3f seconds", timeElapsedSeconds))
27+
println(String.format("-- audio duration: %.3f seconds", audioDuration))
28+
println(String.format("-- real-time factor (RTF): %.3f", realTimeFactor))
29+
30+
stream.release()
31+
recognizer.release()
32+
}
33+
34+
35+
fun createOfflineRecognizer(): OfflineRecognizer {
36+
val modelDir = "./sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01"
37+
val modelConfig = OfflineModelConfig(
38+
cohereTranscribe = OfflineCohereTranscribeModelConfig(
39+
encoder = "$modelDir/encoder.int8.onnx",
40+
decoder = "$modelDir/decoder.int8.onnx",
41+
usePunct = true,
42+
useItn = true,
43+
),
44+
tokens = "$modelDir/tokens.txt",
45+
numThreads = 2,
46+
debug = false,
47+
)
48+
49+
val config = OfflineRecognizerConfig(
50+
modelConfig = modelConfig,
51+
)
52+
53+
return OfflineRecognizer(config = config)
54+
}

sherpa-onnx/csrc/session.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ Ort::SessionOptions GetSessionOptionsImpl(
172172
}
173173

174174
if (config.find("ProfilingFilePrefix") != config.end()) {
175-
sess_opts.EnableProfiling(config["ProfilingFilePrefix"].c_str());
175+
sess_opts.EnableProfiling(SHERPA_ONNX_TO_ORT_PATH(config["ProfilingFilePrefix"]));
176176
config.erase("ProfilingFilePrefix");
177177
}
178178

sherpa-onnx/java-api/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ java_files += OnlineRecognizerConfig.java
3131
java_files += OnlineRecognizerResult.java
3232
java_files += OnlineRecognizer.java
3333

34-
java_files += OfflineTransducerModelConfig.java
34+
java_files += OfflineCohereTranscribeModelConfig.java
3535
java_files += OfflineParaformerModelConfig.java
36+
java_files += OfflineTransducerModelConfig.java
3637
java_files += OfflineWhisperModelConfig.java
3738
java_files += OfflineFireRedAsrModelConfig.java
3839
java_files += OfflineMoonshineModelConfig.java
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.k2fsa.sherpa.onnx;
2+
3+
public class OfflineCohereTranscribeModelConfig {
4+
private final String encoder;
5+
private final String decoder;
6+
private final String language;
7+
private final boolean usePunct;
8+
private final boolean useItn;
9+
10+
private OfflineCohereTranscribeModelConfig(Builder builder) {
11+
this.encoder = builder.encoder;
12+
this.decoder = builder.decoder;
13+
this.language = builder.language;
14+
this.usePunct = builder.usePunct;
15+
this.useItn = builder.useItn;
16+
}
17+
18+
public static Builder builder() {
19+
return new Builder();
20+
}
21+
22+
public String getEncoder() {
23+
return encoder;
24+
}
25+
26+
public String getDecoder() {
27+
return decoder;
28+
}
29+
30+
public String getLanguage() {
31+
return language;
32+
}
33+
34+
public boolean isUsePunct() {
35+
return usePunct;
36+
}
37+
38+
public boolean isUseItn() {
39+
return useItn;
40+
}
41+
42+
public static class Builder {
43+
private String encoder = "";
44+
private String decoder = "";
45+
private String language = "";
46+
private boolean usePunct = true;
47+
private boolean useItn = true;
48+
49+
public OfflineCohereTranscribeModelConfig build() {
50+
return new OfflineCohereTranscribeModelConfig(this);
51+
}
52+
53+
public Builder setEncoder(String encoder) {
54+
this.encoder = encoder;
55+
return this;
56+
}
57+
58+
public Builder setDecoder(String decoder) {
59+
this.decoder = decoder;
60+
return this;
61+
}
62+
63+
public Builder setLanguage(String language) {
64+
this.language = language;
65+
return this;
66+
}
67+
68+
public Builder setUsePunct(boolean usePunct) {
69+
this.usePunct = usePunct;
70+
return this;
71+
}
72+
73+
public Builder setUseItn(boolean useItn) {
74+
this.useItn = useItn;
75+
return this;
76+
}
77+
}
78+
}

sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineModelConfig.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class OfflineModelConfig {
1919
private final OfflineFunAsrNanoModelConfig funasrNano;
2020
private final OfflineQwen3AsrModelConfig qwen3Asr;
2121
private final OfflineCanaryModelConfig canary;
22+
private final OfflineCohereTranscribeModelConfig cohereTranscribe;
2223
private final String teleSpeech;
2324
private final String tokens;
2425
private final int numThreads;
@@ -46,6 +47,7 @@ private OfflineModelConfig(Builder builder) {
4647
this.qwen3Asr = builder.qwen3Asr;
4748
this.senseVoice = builder.senseVoice;
4849
this.dolphin = builder.dolphin;
50+
this.cohereTranscribe = builder.cohereTranscribe;
4951
this.teleSpeech = builder.teleSpeech;
5052
this.tokens = builder.tokens;
5153
this.numThreads = builder.numThreads;
@@ -124,6 +126,10 @@ public OfflineCanaryModelConfig getCanary() {
124126
return canary;
125127
}
126128

129+
public OfflineCohereTranscribeModelConfig getCohereTranscribe() {
130+
return cohereTranscribe;
131+
}
132+
127133
public String getTokens() {
128134
return tokens;
129135
}
@@ -173,6 +179,8 @@ public static class Builder {
173179
private OfflineFunAsrNanoModelConfig funasrNano = OfflineFunAsrNanoModelConfig.builder().build();
174180
private OfflineQwen3AsrModelConfig qwen3Asr = OfflineQwen3AsrModelConfig.builder().build();
175181
private OfflineCanaryModelConfig canary = OfflineCanaryModelConfig.builder().build();
182+
private OfflineCohereTranscribeModelConfig cohereTranscribe =
183+
OfflineCohereTranscribeModelConfig.builder().build();
176184
private String teleSpeech = "";
177185
private String tokens = "";
178186
private int numThreads = 1;
@@ -246,6 +254,11 @@ public Builder setCanary(OfflineCanaryModelConfig canary) {
246254
return this;
247255
}
248256

257+
public Builder setCohereTranscribe(OfflineCohereTranscribeModelConfig cohereTranscribe) {
258+
this.cohereTranscribe = cohereTranscribe;
259+
return this;
260+
}
261+
249262
public Builder setTeleSpeech(String teleSpeech) {
250263
this.teleSpeech = teleSpeech;
251264
return this;

0 commit comments

Comments
 (0)