whisper.rn 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +82 -0
  3. package/android/build.gradle +85 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/com/rnwhisper/RNWhisperModule.java +175 -0
  7. package/android/src/main/java/com/rnwhisper/RNWhisperPackage.java +28 -0
  8. package/android/src/main/java/com/rnwhisper/WhisperContext.java +186 -0
  9. package/android/src/main/jni/whisper/Android.mk +26 -0
  10. package/android/src/main/jni/whisper/Application.mk +1 -0
  11. package/android/src/main/jni/whisper/Whisper.mk +18 -0
  12. package/android/src/main/jni/whisper/jni.c +159 -0
  13. package/ios/RNWhisper.h +9 -0
  14. package/ios/RNWhisper.mm +199 -0
  15. package/ios/RNWhisper.xcodeproj/project.pbxproj +278 -0
  16. package/ios/RNWhisper.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
  17. package/ios/RNWhisper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  18. package/ios/RNWhisper.xcodeproj/project.xcworkspace/xcuserdata/jhen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  19. package/ios/RNWhisper.xcodeproj/xcuserdata/jhen.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  20. package/jest/mock.js +12 -0
  21. package/lib/commonjs/index.js +42 -0
  22. package/lib/commonjs/index.js.map +1 -0
  23. package/lib/module/index.js +35 -0
  24. package/lib/module/index.js.map +1 -0
  25. package/lib/typescript/index.d.ts +28 -0
  26. package/lib/typescript/index.d.ts.map +1 -0
  27. package/package.json +132 -0
  28. package/src/index.tsx +63 -0
  29. package/whisper-rn.podspec +41 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Jhen <developer@jhen.me>
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # whisper.rn
2
+
3
+ [![Actions Status](https://github.com/mybigday/whisper.rn/workflows/CI/badge.svg)](https://github.com/mybigday/whisper.rn/actions)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![npm](https://img.shields.io/npm/v/whisper.rn.svg)](https://www.npmjs.com/package/whisper.rn/)
6
+
7
+ React Native binding of [whisper.cpp](https://github.com/ggerganov/whisper.cpp).
8
+
9
+ [whisper.cpp](https://github.com/ggerganov/whisper.cpp): High-performance inference of [OpenAI's Whisper](https://github.com/openai/whisper) automatic speech recognition (ASR) model
10
+
11
+ <img src="https://user-images.githubusercontent.com/3001525/225511664-8b2ba3ec-864d-4f55-bcb0-447aef168a32.jpeg" width="500" />
12
+
13
+ > Run example with release mode on iPhone 13 Pro Max
14
+
15
+ ## Installation
16
+
17
+ ```sh
18
+ npm install whisper.rn
19
+ ```
20
+
21
+ Then re-run `npx pod-install` again for iOS.
22
+
23
+ ## Usage
24
+
25
+ ```js
26
+ import { initWhisper } from 'whisper.rn'
27
+
28
+ const filePath = 'file://.../ggml.base.en.bin'
29
+ const sampleFilePath = 'file://.../sample.wav'
30
+
31
+ const whisperContext = await initWhisper({ filePath })
32
+
33
+ const { result } = await whisperContext.transcribe(sampleFilePath, {
34
+ language: 'en',
35
+ // More options
36
+ })
37
+ // result: (The inference text result from audio file)
38
+ ```
39
+
40
+ ## Run with example
41
+
42
+ The example app is using [react-native-fs](https://github.com/itinance/react-native-fs) to download the model file and audio file.
43
+
44
+ Model: `base.en` in https://huggingface.co/datasets/ggerganov/whisper.cpp
45
+ Sample file: `jfk.wav` in https://github.com/ggerganov/whisper.cpp/tree/master/samples
46
+
47
+ For test better performance on transcribe, you can run the app in Release mode.
48
+ - iOS: `yarn example ios --configuration Release`
49
+ - Android: `yarn example android --mode release`
50
+
51
+ Please follow [CONTIBUTING.md](./CONTRIBUTING.md#development-workflow) to run the example app.
52
+
53
+ ## Mock `whisper.rn`
54
+
55
+ We have provided a mock version of `whisper.rn` for testing purpose you can use on Jest:
56
+
57
+ ```js
58
+ jest.mock('whisper.rn', () => require('whisper.rn/jest/mock'))
59
+ ```
60
+
61
+ ## Contributing
62
+
63
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
64
+
65
+ ## License
66
+
67
+ MIT
68
+
69
+ ---
70
+
71
+ Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
72
+
73
+ ---
74
+
75
+ <p align="center">
76
+ <a href="https://bricks.tools">
77
+ <img width="90px" src="https://avatars.githubusercontent.com/u/17320237?s=200&v=4">
78
+ </a>
79
+ <p align="center">
80
+ Built and maintained by <a href="https://bricks.tools">BRICKS</a>.
81
+ </p>
82
+ </p>
@@ -0,0 +1,85 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+
7
+ dependencies {
8
+ classpath "com.android.tools.build:gradle:7.2.1"
9
+ }
10
+ }
11
+
12
+ def isNewArchitectureEnabled() {
13
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
14
+ }
15
+
16
+ apply plugin: "com.android.library"
17
+
18
+
19
+ def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
20
+
21
+ if (isNewArchitectureEnabled()) {
22
+ apply plugin: "com.facebook.react"
23
+ }
24
+
25
+ def getExtOrDefault(name) {
26
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["RNWhisper_" + name]
27
+ }
28
+
29
+ def getExtOrIntegerDefault(name) {
30
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RNWhisper_" + name]).toInteger()
31
+ }
32
+
33
+ android {
34
+ ndkVersion getExtOrDefault("ndkVersion")
35
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
36
+
37
+ defaultConfig {
38
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
39
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
40
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
41
+ }
42
+ externalNativeBuild {
43
+ externalNativeBuild {
44
+ ndkBuild {
45
+ path 'src/main/jni/whisper/Android.mk'
46
+ }
47
+ }
48
+ }
49
+ buildTypes {
50
+ release {
51
+ minifyEnabled false
52
+ }
53
+ }
54
+
55
+ lintOptions {
56
+ disable "GradleCompatible"
57
+ }
58
+
59
+ compileOptions {
60
+ sourceCompatibility JavaVersion.VERSION_1_8
61
+ targetCompatibility JavaVersion.VERSION_1_8
62
+ }
63
+
64
+ }
65
+
66
+ repositories {
67
+ mavenCentral()
68
+ google()
69
+ }
70
+
71
+
72
+ dependencies {
73
+ // For < 0.71, this will be from the local maven repo
74
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
75
+ //noinspection GradleDynamicVersion
76
+ implementation "com.facebook.react:react-native:+"
77
+ }
78
+
79
+ if (isNewArchitectureEnabled()) {
80
+ react {
81
+ jsRootDir = file("../src/")
82
+ libraryName = "RNWhisper"
83
+ codegenJavaPackageName = "com.rnwhisper"
84
+ }
85
+ }
@@ -0,0 +1,5 @@
1
+ RNWhisper_kotlinVersion=1.7.0
2
+ RNWhisper_minSdkVersion=23
3
+ RNWhisper_targetSdkVersion=31
4
+ RNWhisper_compileSdkVersion=31
5
+ RNWhisper_ndkversion=25.1.8937393
@@ -0,0 +1,4 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.rnwhisper">
3
+
4
+ </manifest>
@@ -0,0 +1,175 @@
1
+ package com.rnwhisper;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import android.util.Log;
5
+ import android.os.Build;
6
+ import android.os.Handler;
7
+ import android.os.AsyncTask;
8
+
9
+ import com.facebook.react.bridge.Promise;
10
+ import com.facebook.react.bridge.ReactApplicationContext;
11
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
12
+ import com.facebook.react.bridge.ReactMethod;
13
+ import com.facebook.react.bridge.LifecycleEventListener;
14
+ import com.facebook.react.bridge.ReadableMap;
15
+ import com.facebook.react.module.annotations.ReactModule;
16
+
17
+ import java.util.HashMap;
18
+ import java.util.Random;
19
+
20
+ @ReactModule(name = RNWhisperModule.NAME)
21
+ public class RNWhisperModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
22
+ public static final String NAME = "RNWhisper";
23
+
24
+ private ReactApplicationContext reactContext;
25
+
26
+ public RNWhisperModule(ReactApplicationContext reactContext) {
27
+ super(reactContext);
28
+ reactContext.addLifecycleEventListener(this);
29
+ this.reactContext = reactContext;
30
+ }
31
+
32
+ @Override
33
+ @NonNull
34
+ public String getName() {
35
+ return NAME;
36
+ }
37
+
38
+ private HashMap<Integer, WhisperContext> contexts = new HashMap<>();
39
+
40
+ @ReactMethod
41
+ public void initContext(final String modelPath, final Promise promise) {
42
+ new AsyncTask<Void, Void, Integer>() {
43
+ private Exception exception;
44
+
45
+ @Override
46
+ protected Integer doInBackground(Void... voids) {
47
+ try {
48
+ long context = WhisperContext.initContext(modelPath);
49
+ if (context == 0) {
50
+ throw new Exception("Failed to initialize context");
51
+ }
52
+ int id = Math.abs(new Random().nextInt());
53
+ WhisperContext whisperContext = new WhisperContext(context);
54
+ contexts.put(id, whisperContext);
55
+ return id;
56
+ } catch (Exception e) {
57
+ exception = e;
58
+ return null;
59
+ }
60
+ }
61
+
62
+ @Override
63
+ protected void onPostExecute(Integer id) {
64
+ if (exception != null) {
65
+ promise.reject(exception);
66
+ return;
67
+ }
68
+ promise.resolve(id);
69
+ }
70
+ }.execute();
71
+ }
72
+
73
+ @ReactMethod
74
+ public void transcribe(int id, String filePath, ReadableMap options, Promise promise) {
75
+ new AsyncTask<Void, Void, String>() {
76
+ private Exception exception;
77
+
78
+ @Override
79
+ protected String doInBackground(Void... voids) {
80
+ try {
81
+ WhisperContext context = contexts.get(id);
82
+ if (context == null) {
83
+ throw new Exception("Context " + id + " not found");
84
+ }
85
+ return context.transcribe(filePath, options);
86
+ } catch (Exception e) {
87
+ exception = e;
88
+ return null;
89
+ }
90
+ }
91
+
92
+ @Override
93
+ protected void onPostExecute(String result) {
94
+ if (exception != null) {
95
+ promise.reject(exception);
96
+ return;
97
+ }
98
+ promise.resolve(result);
99
+ }
100
+ }.execute();
101
+ }
102
+
103
+ @ReactMethod
104
+ public void releaseContext(int id, Promise promise) {
105
+ new AsyncTask<Void, Void, Void>() {
106
+ private Exception exception;
107
+
108
+ @Override
109
+ protected Void doInBackground(Void... voids) {
110
+ try {
111
+ WhisperContext context = contexts.get(id);
112
+ if (context == null) {
113
+ throw new Exception("Context " + id + " not found");
114
+ }
115
+ context.release();
116
+ contexts.remove(id);
117
+ } catch (Exception e) {
118
+ exception = e;
119
+ }
120
+ return null;
121
+ }
122
+
123
+ @Override
124
+ protected void onPostExecute(Void result) {
125
+ if (exception != null) {
126
+ promise.reject(exception);
127
+ return;
128
+ }
129
+ promise.resolve(null);
130
+ }
131
+ }.execute();
132
+ }
133
+
134
+ @ReactMethod
135
+ public void releaseAllContexts(Promise promise) {
136
+ new AsyncTask<Void, Void, Void>() {
137
+ private Exception exception;
138
+
139
+ @Override
140
+ protected Void doInBackground(Void... voids) {
141
+ try {
142
+ onHostDestroy();
143
+ } catch (Exception e) {
144
+ exception = e;
145
+ }
146
+ return null;
147
+ }
148
+
149
+ @Override
150
+ protected void onPostExecute(Void result) {
151
+ if (exception != null) {
152
+ promise.reject(exception);
153
+ return;
154
+ }
155
+ promise.resolve(null);
156
+ }
157
+ }.execute();
158
+ }
159
+
160
+ @Override
161
+ public void onHostResume() {
162
+ }
163
+
164
+ @Override
165
+ public void onHostPause() {
166
+ }
167
+
168
+ @Override
169
+ public void onHostDestroy() {
170
+ for (WhisperContext context : contexts.values()) {
171
+ context.release();
172
+ }
173
+ contexts.clear();
174
+ }
175
+ }
@@ -0,0 +1,28 @@
1
+ package com.rnwhisper;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ import com.facebook.react.ReactPackage;
6
+ import com.facebook.react.bridge.NativeModule;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.uimanager.ViewManager;
9
+
10
+ import java.util.ArrayList;
11
+ import java.util.Collections;
12
+ import java.util.List;
13
+
14
+ public class RNWhisperPackage implements ReactPackage {
15
+ @NonNull
16
+ @Override
17
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
18
+ List<NativeModule> modules = new ArrayList<>();
19
+ modules.add(new RNWhisperModule(reactContext));
20
+ return modules;
21
+ }
22
+
23
+ @NonNull
24
+ @Override
25
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
26
+ return Collections.emptyList();
27
+ }
28
+ }
@@ -0,0 +1,186 @@
1
+ package com.rnwhisper;
2
+
3
+ import com.facebook.react.bridge.ReadableMap;
4
+
5
+ import android.util.Log;
6
+ import android.os.Build;
7
+ import android.content.res.AssetManager;
8
+
9
+ import java.util.Random;
10
+ import java.lang.StringBuilder;
11
+ import java.io.File;
12
+ import java.io.BufferedReader;
13
+ import java.io.IOException;
14
+ import java.io.FileReader;
15
+ import java.io.ByteArrayOutputStream;
16
+ import java.io.File;
17
+ import java.io.FileInputStream;
18
+ import java.io.IOException;
19
+ import java.io.InputStream;
20
+ import java.nio.ByteBuffer;
21
+ import java.nio.ByteOrder;
22
+ import java.nio.ShortBuffer;
23
+
24
+ public class WhisperContext {
25
+ public static final String NAME = "RNWhisperContext";
26
+ private long context;
27
+
28
+ public WhisperContext(long context) {
29
+ this.context = context;
30
+ }
31
+
32
+ public String transcribe(final String filePath, final ReadableMap options) throws IOException, Exception {
33
+ int code = fullTranscribe(
34
+ context,
35
+ decodeWaveFile(new File(filePath)),
36
+ // jint n_threads,
37
+ options.hasKey("maxThreads") ? options.getInt("maxThreads") : -1,
38
+ // jint max_context,
39
+ options.hasKey("maxContext") ? options.getInt("maxContext") : -1,
40
+ // jint max_len,
41
+ options.hasKey("maxLen") ? options.getInt("maxLen") : -1,
42
+ // jint offset,
43
+ options.hasKey("offset") ? options.getInt("offset") : -1,
44
+ // jint duration,
45
+ options.hasKey("duration") ? options.getInt("duration") : -1,
46
+ // jint word_thold,
47
+ options.hasKey("wordThold") ? options.getInt("wordThold") : -1,
48
+ // jfloat temperature,
49
+ options.hasKey("temperature") ? (float) options.getDouble("temperature") : -1.0f,
50
+ // jfloat temperature_inc,
51
+ options.hasKey("temperatureInc") ? (float) options.getDouble("temperatureInc") : -1.0f,
52
+ // jint beam_size,
53
+ options.hasKey("beamSize") ? options.getInt("beamSize") : -1,
54
+ // jint best_of,
55
+ options.hasKey("bestOf") ? options.getInt("bestOf") : -1,
56
+ // jboolean speed_up,
57
+ options.hasKey("speedUp") ? options.getBoolean("speedUp") : false,
58
+ // jboolean translate,
59
+ options.hasKey("translate") ? options.getBoolean("translate") : false,
60
+ // jstring language,
61
+ options.hasKey("language") ? options.getString("language") : "auto"
62
+ );
63
+ if (code != 0) {
64
+ throw new Exception("Transcription failed with code " + code);
65
+ }
66
+ Integer count = getTextSegmentCount(context);
67
+ StringBuilder builder = new StringBuilder();
68
+ for (int i = 0; i < count; i++) {
69
+ builder.append(getTextSegment(context, i));
70
+ }
71
+ return builder.toString();
72
+ }
73
+
74
+ public void release() {
75
+ freeContext(context);
76
+ }
77
+
78
+ public static float[] decodeWaveFile(File file) throws IOException {
79
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
80
+ try (InputStream inputStream = new FileInputStream(file)) {
81
+ byte[] buffer = new byte[1024];
82
+ int bytesRead;
83
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
84
+ baos.write(buffer, 0, bytesRead);
85
+ }
86
+ }
87
+ ByteBuffer byteBuffer = ByteBuffer.wrap(baos.toByteArray());
88
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
89
+ byteBuffer.position(44);
90
+ ShortBuffer shortBuffer = byteBuffer.asShortBuffer();
91
+ short[] shortArray = new short[shortBuffer.limit()];
92
+ shortBuffer.get(shortArray);
93
+ float[] floatArray = new float[shortArray.length];
94
+ for (int i = 0; i < shortArray.length; i++) {
95
+ floatArray[i] = ((float) shortArray[i]) / 32767.0f;
96
+ floatArray[i] = Math.max(floatArray[i], -1f);
97
+ floatArray[i] = Math.min(floatArray[i], 1f);
98
+ }
99
+ return floatArray;
100
+ }
101
+
102
+ static {
103
+ Log.d(NAME, "Primary ABI: " + Build.SUPPORTED_ABIS[0]);
104
+ boolean loadVfpv4 = false;
105
+ boolean loadV8fp16 = false;
106
+ if (isArmeabiV7a()) {
107
+ // armeabi-v7a needs runtime detection support
108
+ String cpuInfo = cpuInfo();
109
+ if (cpuInfo != null) {
110
+ Log.d(NAME, "CPU info: " + cpuInfo);
111
+ if (cpuInfo.contains("vfpv4")) {
112
+ Log.d(NAME, "CPU supports vfpv4");
113
+ loadVfpv4 = true;
114
+ }
115
+ }
116
+ } else if (isArmeabiV8a()) {
117
+ // ARMv8.2a needs runtime detection support
118
+ String cpuInfo = cpuInfo();
119
+ if (cpuInfo != null) {
120
+ Log.d(NAME, "CPU info: " + cpuInfo);
121
+ if (cpuInfo.contains("fphp")) {
122
+ Log.d(NAME, "CPU supports fp16 arithmetic");
123
+ loadV8fp16 = true;
124
+ }
125
+ }
126
+ }
127
+
128
+ if (loadVfpv4) {
129
+ Log.d(NAME, "Loading libwhisper_vfpv4.so");
130
+ System.loadLibrary("whisper_vfpv4");
131
+ } else if (loadV8fp16) {
132
+ Log.d(NAME, "Loading libwhisper_v8fp16_va.so");
133
+ System.loadLibrary("whisper_v8fp16_va");
134
+ } else {
135
+ Log.d(NAME, "Loading libwhisper.so");
136
+ System.loadLibrary("whisper");
137
+ }
138
+ }
139
+
140
+ private static boolean isArmeabiV7a() {
141
+ return Build.SUPPORTED_ABIS[0].equals("armeabi-v7a");
142
+ }
143
+
144
+ private static boolean isArmeabiV8a() {
145
+ return Build.SUPPORTED_ABIS[0].equals("arm64-v8a");
146
+ }
147
+
148
+ private static String cpuInfo() {
149
+ File file = new File("/proc/cpuinfo");
150
+ StringBuilder stringBuilder = new StringBuilder();
151
+ try {
152
+ BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
153
+ String line;
154
+ while ((line = bufferedReader.readLine()) != null) {
155
+ stringBuilder.append(line);
156
+ }
157
+ bufferedReader.close();
158
+ return stringBuilder.toString();
159
+ } catch (IOException e) {
160
+ Log.w(NAME, "Couldn't read /proc/cpuinfo", e);
161
+ return null;
162
+ }
163
+ }
164
+
165
+ protected static native long initContext(String modelPath);
166
+ protected static native int fullTranscribe(
167
+ long context,
168
+ float[] audio_data,
169
+ int n_threads,
170
+ int max_context,
171
+ int max_len,
172
+ int offset,
173
+ int duration,
174
+ int word_thold,
175
+ float temperature,
176
+ float temperature_inc,
177
+ int beam_size,
178
+ int best_of,
179
+ boolean speed_up,
180
+ boolean translate,
181
+ String language
182
+ );
183
+ protected static native int getTextSegmentCount(long context);
184
+ protected static native String getTextSegment(long context, int index);
185
+ protected static native void freeContext(long contextPtr);
186
+ }
@@ -0,0 +1,26 @@
1
+ LOCAL_PATH := $(call my-dir)
2
+ include $(CLEAR_VARS)
3
+ LOCAL_MODULE := libwhisper
4
+ include $(LOCAL_PATH)/Whisper.mk
5
+ include $(BUILD_SHARED_LIBRARY)
6
+
7
+ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
8
+ include $(CLEAR_VARS)
9
+ LOCAL_MODULE := libwhisper_vfpv4
10
+ include $(LOCAL_PATH)/Whisper.mk
11
+ # Allow building NEON FMA code.
12
+ # https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h
13
+ LOCAL_CFLAGS += -mfpu=neon-vfpv4
14
+ include $(BUILD_SHARED_LIBRARY)
15
+ endif
16
+
17
+ ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
18
+ include $(CLEAR_VARS)
19
+ LOCAL_MODULE := libwhisper_v8fp16_va
20
+ include $(LOCAL_PATH)/Whisper.mk
21
+ # Allow building NEON FMA code.
22
+ # https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h
23
+ LOCAL_CFLAGS += -march=armv8.2-a+fp16
24
+ include $(BUILD_SHARED_LIBRARY)
25
+ endif
26
+
@@ -0,0 +1 @@
1
+ APP_STL := c++_static
@@ -0,0 +1,18 @@
1
+ WHISPER_LIB_DIR := $(LOCAL_PATH)/../../../../../cpp
2
+ LOCAL_LDLIBS := -landroid -llog
3
+
4
+ # Make the final output library smaller by only keeping the symbols referenced from the app.
5
+ ifneq ($(APP_OPTIM),debug)
6
+ LOCAL_CFLAGS += -O3
7
+ LOCAL_CFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
8
+ LOCAL_CFLAGS += -ffunction-sections -fdata-sections
9
+ LOCAL_LDFLAGS += -Wl,--gc-sections
10
+ LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
11
+ LOCAL_LDFLAGS += -flto
12
+ endif
13
+
14
+ LOCAL_CFLAGS += -DSTDC_HEADERS -std=c11 -I $(WHISPER_LIB_DIR)
15
+ LOCAL_CPPFLAGS += -std=c++11
16
+ LOCAL_SRC_FILES := $(WHISPER_LIB_DIR)/ggml.c \
17
+ $(WHISPER_LIB_DIR)/whisper.cpp \
18
+ $(LOCAL_PATH)/jni.c