Skip to content

Commit 42814f3

Browse files
author
litongjava
committed
release to v1.0.1
1 parent 98cbb1d commit 42814f3

File tree

9 files changed

+220
-1749
lines changed

9 files changed

+220
-1749
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.litongjava.whisper.cpp.android.java.bean;
2+
3+
/**
4+
* Created by [email protected] on 10/21/2023_7:48 AM
5+
*/
6+
public class WhisperSegment {
7+
private long start, end;
8+
private String sentence;
9+
10+
public WhisperSegment() {
11+
}
12+
13+
public WhisperSegment(long start, long end, String sentence) {
14+
this.start = start;
15+
this.end = end;
16+
this.sentence = sentence;
17+
}
18+
19+
public long getStart() {
20+
return start;
21+
}
22+
23+
public long getEnd() {
24+
return end;
25+
}
26+
27+
public String getSentence() {
28+
return sentence;
29+
}
30+
31+
public void setStart(long start) {
32+
this.start = start;
33+
}
34+
35+
public void setEnd(long end) {
36+
this.end = end;
37+
}
38+
39+
public void setSentence(String sentence) {
40+
this.sentence = sentence;
41+
}
42+
43+
@Override
44+
public String toString() {
45+
return "["+start+" --> "+end+"]:"+sentence;
46+
}
47+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.litongjava.whisper.cpp.android.java.demo.app;
2+
3+
import android.app.Application;
4+
5+
import com.blankj.utilcode.util.Utils;
6+
7+
public class App extends Application {
8+
@Override
9+
public void onCreate() {
10+
super.onCreate();
11+
Utils.init(this);
12+
}
13+
}

app/src/main/java/com/litongjava/whisper/cpp/android/java/services/WhisperService.java

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,101 +6,89 @@
66

77
import androidx.annotation.RequiresApi;
88

9+
import com.litongjava.whisper.cpp.android.java.bean.WhisperSegment;
910
import com.litongjava.whisper.cpp.android.java.media.WaveEncoder;
11+
import com.litongjava.whisper.cpp.android.java.single.LocalWhisper;
1012
import com.litongjava.whisper.cpp.android.java.utils.AssetUtils;
11-
import com.whispercppdemo.whisper.WhisperContext;
1213

1314
import org.slf4j.Logger;
1415
import org.slf4j.LoggerFactory;
1516

1617
import java.io.File;
1718
import java.io.IOException;
19+
import java.util.List;
1820
import java.util.concurrent.ExecutionException;
1921

2022
public class WhisperService {
2123
private Logger log = LoggerFactory.getLogger(this.getClass());
22-
private WhisperContext whisperContext;
24+
25+
private final Object lock = new Object();
2326

2427
@RequiresApi(api = Build.VERSION_CODES.O)
2528
public void loadModel(Context context, TextView tv) {
29+
String modelFilePath = LocalWhisper.modelFilePath;
30+
String msg = "load model from :" + modelFilePath + "\n";
31+
outputMsg(tv, msg);
2632

27-
File filesDir = context.getFilesDir();
28-
String modelFilePath = "models/ggml-tiny.bin";
29-
File modelFile = AssetUtils.copyFileIfNotExists(context, filesDir, modelFilePath);
30-
modelFilePath = modelFile.getAbsolutePath();
33+
long start = System.currentTimeMillis();
34+
LocalWhisper.INSTANCE.init();
35+
long end = System.currentTimeMillis();
36+
msg = "model load successful:" + (end - start) + "ms";
37+
outputMsg(tv, msg);
3138

32-
String msg = "load model from :" + modelFilePath + "\n";
33-
log.info(msg);
34-
tv.append(msg);
35-
if (whisperContext == null) {
36-
long start = System.currentTimeMillis();
37-
whisperContext = WhisperContext.createContextFromFile(modelFilePath);
38-
// AopManager.me().addSingletonObject(whisperContext);
39-
long end = System.currentTimeMillis();
40-
msg = "model load successful:" + (end - start) + "ms\n";
41-
log.info(msg);
42-
tv.append(msg);
43-
} else {
44-
msg = "model loaded\n";
45-
log.info(msg);
46-
tv.append(msg);
47-
}
4839
}
4940

5041
public void transcribeSample(Context context, TextView tv) {
42+
String msg = "";
43+
long start = System.currentTimeMillis();
5144
String sampleFilePath = "samples/jfk.wav";
5245
File filesDir = context.getFilesDir();
5346
File sampleFile = AssetUtils.copyFileIfNotExists(context, filesDir, sampleFilePath);
54-
log.info("transcribe file from :{}", sampleFile.getAbsolutePath());
47+
long end = System.currentTimeMillis();
48+
msg = "copy file:" + (end - start) + "ms";
49+
outputMsg(tv, msg);
50+
51+
msg = "transcribe file from :" + sampleFile.getAbsolutePath();
52+
outputMsg(tv, msg);
53+
54+
start = System.currentTimeMillis();
5555
float[] audioData = new float[0]; // 读取音频样本
5656
try {
5757
audioData = WaveEncoder.decodeWaveFile(sampleFile);
5858
} catch (IOException e) {
5959
e.printStackTrace();
60+
return;
6061
}
62+
end = System.currentTimeMillis();
63+
msg = "decode wave file:" + (end - start) + "ms";
64+
outputMsg(tv, msg);
6165

62-
String transcription = null; // 转录音频数据
63-
64-
String msg = "";
66+
start = System.currentTimeMillis();
67+
List<WhisperSegment> transcription = null;
6568
try {
66-
if (whisperContext == null) {
67-
msg = "please load model or wait model loaded";
68-
log.info(msg);
69-
70-
} else {
71-
long start = System.currentTimeMillis();
72-
transcription = whisperContext.transcribeData(audioData);
73-
long end = System.currentTimeMillis();
74-
msg = "Transcript successful:" + (end - start) + "ms";
75-
log.info(msg);
76-
tv.append(msg + "\n");
77-
78-
msg = "Transcription:" + transcription;
79-
log.info(msg);
80-
tv.append(msg + "\n");
81-
}
82-
8369

70+
//transcription = LocalWhisper.INSTANCE.transcribeData(audioData);
71+
transcription = LocalWhisper.INSTANCE.transcribeDataWithTime(audioData);
8472
} catch (ExecutionException e) {
8573
e.printStackTrace();
8674
} catch (InterruptedException e) {
8775
e.printStackTrace();
8876
}
77+
end = System.currentTimeMillis();
78+
msg = "Transcript successful:" + (end - start) + "ms";
79+
outputMsg(tv, msg);
8980

81+
msg = "Transcription:" + transcription.toString();
82+
outputMsg(tv, msg);
83+
}
9084

85+
private void outputMsg(TextView tv, String msg) {
86+
tv.append(msg + "\n");
87+
log.info(msg);
9188
}
9289

9390
@RequiresApi(api = Build.VERSION_CODES.O)
9491
public void release() {
95-
if (whisperContext != null) {
96-
try {
97-
whisperContext.release();
98-
} catch (ExecutionException e) {
99-
e.printStackTrace();
100-
} catch (InterruptedException e) {
101-
e.printStackTrace();
102-
}
103-
whisperContext = null;
104-
}
92+
//noting to do
10593
}
106-
}
94+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.litongjava.whisper.cpp.android.java.single;
2+
3+
import android.app.Application;
4+
import android.os.Build;
5+
6+
import androidx.annotation.RequiresApi;
7+
8+
import com.blankj.utilcode.util.Utils;
9+
import com.litongjava.whisper.cpp.android.java.bean.WhisperSegment;
10+
import com.litongjava.whisper.cpp.android.java.utils.AssetUtils;
11+
import com.whispercppdemo.whisper.WhisperContext;
12+
13+
import java.io.File;
14+
import java.util.List;
15+
import java.util.concurrent.ExecutionException;
16+
17+
//import com.litongjava.whisper.android.java.bean.WhisperSegment;
18+
//import com.litongjava.whisper.android.java.utils.AssetUtils;
19+
20+
public enum LocalWhisper {
21+
INSTANCE;
22+
23+
public static final String modelFilePath = "models/ggml-tiny.bin";
24+
private WhisperContext whisperContext;
25+
26+
@RequiresApi(api = Build.VERSION_CODES.O)
27+
LocalWhisper() {
28+
Application context = Utils.getApp();
29+
File filesDir = context.getFilesDir();
30+
File modelFile = AssetUtils.copyFileIfNotExists(context, filesDir, modelFilePath);
31+
String realModelFilePath = modelFile.getAbsolutePath();
32+
whisperContext = WhisperContext.createContextFromFile(realModelFilePath);
33+
}
34+
35+
public synchronized String transcribeData(float[] data) throws ExecutionException, InterruptedException {
36+
return whisperContext.transcribeData(data);
37+
}
38+
39+
public List<WhisperSegment> transcribeDataWithTime(float[] audioData) throws ExecutionException, InterruptedException {
40+
return whisperContext.transcribeDataWithTime(audioData);
41+
}
42+
43+
public void init() {
44+
//noting to do.but init
45+
}
46+
47+
48+
}

app/src/main/java/com/whispercppdemo/whisper/WhisperContext.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66

77
import androidx.annotation.RequiresApi;
88

9+
import com.litongjava.whisper.cpp.android.java.bean.WhisperSegment;
10+
911
import java.io.InputStream;
12+
import java.util.ArrayList;
13+
import java.util.List;
1014
import java.util.concurrent.Callable;
1115
import java.util.concurrent.ExecutionException;
1216
import java.util.concurrent.ExecutorService;
@@ -33,17 +37,53 @@ public String call() throws Exception {
3337
}
3438
int numThreads = WhisperCpuConfig.getPreferredThreadCount();
3539
Log.d(LOG_TAG, "Selecting " + numThreads + " threads");
36-
WhisperLib.fullTranscribe(ptr, numThreads, data);
37-
int textCount = WhisperLib.getTextSegmentCount(ptr);
40+
3841
StringBuilder result = new StringBuilder();
39-
for (int i = 0; i < textCount; i++) {
40-
result.append(WhisperLib.getTextSegment(ptr, i));
42+
synchronized (this) {
43+
44+
WhisperLib.fullTranscribe(ptr, numThreads, data);
45+
int textCount = WhisperLib.getTextSegmentCount(ptr);
46+
for (int i = 0; i < textCount; i++) {
47+
String sentence = WhisperLib.getTextSegment(ptr, i);
48+
result.append(sentence);
49+
}
4150
}
4251
return result.toString();
4352
}
4453
}).get();
4554
}
4655

56+
public List<WhisperSegment> transcribeDataWithTime(float[] data) throws ExecutionException, InterruptedException {
57+
return executorService.submit(new Callable<List<WhisperSegment>>() {
58+
@RequiresApi(api = Build.VERSION_CODES.O)
59+
@Override
60+
public List<WhisperSegment> call() throws Exception {
61+
if (ptr == 0L) {
62+
throw new IllegalStateException();
63+
}
64+
int numThreads = WhisperCpuConfig.getPreferredThreadCount();
65+
Log.d(LOG_TAG, "Selecting " + numThreads + " threads");
66+
67+
List<WhisperSegment> segments = new ArrayList<>();
68+
synchronized (this) {
69+
// StringBuilder result = new StringBuilder();
70+
WhisperLib.fullTranscribe(ptr, numThreads, data);
71+
int textCount = WhisperLib.getTextSegmentCount(ptr);
72+
for (int i = 0; i < textCount; i++) {
73+
long start = WhisperLib.getTextSegmentT0(ptr, i);
74+
String sentence = WhisperLib.getTextSegment(ptr, i);
75+
long end = WhisperLib.getTextSegmentT1(ptr, i);
76+
// result.append();
77+
segments.add(new WhisperSegment(start, end, sentence));
78+
79+
}
80+
// return result.toString();
81+
}
82+
return segments;
83+
}
84+
}).get();
85+
}
86+
4787
@RequiresApi(api = Build.VERSION_CODES.O)
4888
public String benchMemory(int nthreads) throws ExecutionException, InterruptedException {
4989
return executorService.submit(() -> WhisperLib.benchMemcpy(nthreads)).get();

app/src/main/java/com/whispercppdemo/whisper/WhisperLib.java

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,45 @@
66

77
import androidx.annotation.RequiresApi;
88

9-
import org.slf4j.Logger;
10-
import org.slf4j.LoggerFactory;
11-
129
import java.io.InputStream;
1310

1411
@RequiresApi(api = Build.VERSION_CODES.O)
1512
public class WhisperLib {
1613
private static final String LOG_TAG = "LibWhisper";
17-
private static Logger log = LoggerFactory.getLogger(WhisperLib.class);
1814

1915
static {
2016

2117
Log.d(LOG_TAG, "Primary ABI: " + Build.SUPPORTED_ABIS[0]);
22-
log.info("Primary ABI: " + Build.SUPPORTED_ABIS[0]);
2318
boolean loadVfpv4 = false;
2419
boolean loadV8fp16 = false;
25-
if (Utils.isArmEabiV7a()) {
26-
String cpuInfo = Utils.cpuInfo();
20+
if (WhisperUtils.isArmEabiV7a()) {
21+
String cpuInfo = WhisperUtils.cpuInfo();
2722
if (cpuInfo != null) {
2823
Log.d(LOG_TAG, "CPU info: " + cpuInfo);
29-
log.info("CPU info: " + cpuInfo);
3024
if (cpuInfo.contains("vfpv4")) {
3125
Log.d(LOG_TAG, "CPU supports vfpv4");
32-
log.info("CPU supports vfpv4");
3326
loadVfpv4 = true;
3427
}
3528
}
36-
} else if (Utils.isArmEabiV8a()) {
37-
String cpuInfo = Utils.cpuInfo();
29+
} else if (WhisperUtils.isArmEabiV8a()) {
30+
String cpuInfo = WhisperUtils.cpuInfo();
3831
if (cpuInfo != null) {
3932
Log.d(LOG_TAG, "CPU info: " + cpuInfo);
40-
log.info("CPU info: " + cpuInfo);
4133
if (cpuInfo.contains("fphp")) {
4234
Log.d(LOG_TAG, "CPU supports fp16 arithmetic");
43-
log.info("CPU supports fp16 arithmetic");
4435
loadV8fp16 = true;
4536
}
4637
}
4738
}
4839

4940
if (loadVfpv4) {
5041
Log.d(LOG_TAG, "Loading libwhisper_vfpv4.so");
51-
log.info("Loading libwhisper_vfpv4.so");
5242
System.loadLibrary("whisper_vfpv4");
5343
} else if (loadV8fp16) {
5444
Log.d(LOG_TAG, "Loading libwhisper_v8fp16_va.so");
55-
log.info("Loading libwhisper_v8fp16_va.so");
5645
System.loadLibrary("whisper_v8fp16_va");
5746
} else {
5847
Log.d(LOG_TAG, "Loading libwhisper.so");
59-
log.info("Loading libwhisper.so");
6048
System.loadLibrary("whisper");
6149
}
6250
}
@@ -75,6 +63,10 @@ public class WhisperLib {
7563

7664
public static native String getTextSegment(long contextPtr, int index);
7765

66+
public static native long getTextSegmentT0(long contextPtr, int index);
67+
68+
public static native long getTextSegmentT1(long contextPtr, int index);
69+
7870
public static native String getSystemInfo();
7971

8072
public static native String benchMemcpy(int nthread);

0 commit comments

Comments
 (0)