Skip to content

Commit 366976e

Browse files
committed
Initial implementation of fasttext for language identification
1 parent 734acbb commit 366976e

9 files changed

Lines changed: 237 additions & 92 deletions

File tree

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
[submodule "app/src/main/cpp/src/libs/protobuf-lite"]
88
path = app/src/main/cpp/src/libs/protobuf-lite
99
url = https://github.com/niedev/protobuf
10+
[submodule "app/src/main/cpp/src/fasttext/libs/fastText"]
11+
path = app/src/main/cpp/src/fasttext/libs/fastText
12+
url = https://github.com/niedev/fastText

app/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ dependencies {
129129
implementation "ai.djl.android:core:0.33.0"
130130
implementation "ai.djl.huggingface:tokenizers:0.33.0"
131131
implementation "ai.djl.android:tokenizer-native:0.33.0"
132+
// DJL fasttext wrapper
133+
implementation 'ai.djl.fasttext:fasttext-engine:0.33.0'
132134
//protobuf
133135
implementation "com.google.protobuf:protobuf-javalite:4.33.5"
134136
// bouncycastle crypto lib
@@ -145,7 +147,7 @@ dependencies {
145147
implementation 'com.microsoft.onnxruntime:onnxruntime-android:1.23.2' //latest.release
146148
implementation 'com.microsoft.onnxruntime:onnxruntime-extensions-android:0.13.0' //latest.release
147149
//Ml-Kit
148-
implementation 'com.google.mlkit:language-id:17.0.5'
150+
//implementation 'com.google.mlkit:language-id:17.0.5'
149151
//JWS parser
150152
implementation group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '5.1'
151153
implementation files('libs/sqlite4java-android-release.aar')

app/src/main/assets/fasttext.ftz

916 KB
Binary file not shown.

app/src/main/cpp/src/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,5 @@ target_link_libraries(cache_container_native
6464
log
6565
)
6666

67-
add_subdirectory(bergamot_translator)
67+
add_subdirectory(bergamot_translator)
68+
add_subdirectory(fasttext)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Grab all fastText C++ source files
2+
file(GLOB FASTTEXT_SRC "libs/fastText/src/*.cc")
3+
4+
# Exclude main.cc (contains the CLI tool's main() function, which will cause a build error)
5+
list(REMOVE_ITEM FASTTEXT_SRC "${CMAKE_CURRENT_SOURCE_DIR}/libs/fastText/src/main.cc")
6+
7+
# Create your shared library, compiling your JNI wrapper AND the fastText source
8+
add_library(
9+
fasttext-lib
10+
SHARED
11+
FastTextWrapper.cpp
12+
${FASTTEXT_SRC}
13+
)
14+
15+
# Link standard Android logging
16+
find_library(log-lib log)
17+
target_link_libraries(fasttext-lib ${log-lib})
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2016 Luca Martino.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copyFile of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <jni.h>
18+
#include <string>
19+
#include <sstream>
20+
#include "libs/fastText/src/fasttext.h"
21+
22+
extern "C" JNIEXPORT jlong JNICALL
23+
Java_nie_translator_rtranslator_voice_1translation_neural_1networks_translation_LanguageDetector_initFastText(JNIEnv* env, jobject /* this */) {
24+
// Return a pointer to the native FastText object
25+
auto* ft = new fasttext::FastText();
26+
return reinterpret_cast<jlong>(ft);
27+
}
28+
29+
extern "C" JNIEXPORT void JNICALL
30+
Java_nie_translator_rtranslator_voice_1translation_neural_1networks_translation_LanguageDetector_loadModel(JNIEnv* env, jobject /* this */, jlong ptr, jstring path) {
31+
auto* ft = reinterpret_cast<fasttext::FastText*>(ptr);
32+
const char* pathStr = env->GetStringUTFChars(path, nullptr);
33+
34+
// Load the .bin or .ftz model
35+
ft->loadModel(pathStr);
36+
env->ReleaseStringUTFChars(path, pathStr);
37+
}
38+
39+
extern "C" JNIEXPORT jstring JNICALL
40+
Java_nie_translator_rtranslator_voice_1translation_neural_1networks_translation_LanguageDetector_predictLanguage(JNIEnv* env, jobject /* this */, jlong ptr, jstring text, jdouble confidenceThreshold) {
41+
auto* ft = reinterpret_cast<fasttext::FastText*>(ptr);
42+
const char* textStr = env->GetStringUTFChars(text, nullptr);
43+
44+
std::stringstream ioss(textStr);
45+
std::vector<std::pair<fasttext::real, std::string>> predictions;
46+
47+
// Predict the single most likely language (k = 1)
48+
ft->predictLine(ioss, predictions, 1, confidenceThreshold);
49+
env->ReleaseStringUTFChars(text, textStr);
50+
51+
if (!predictions.empty()) {
52+
std::string label = predictions[0].second;
53+
// fastText returns labels like "__label__en". We strip the prefix.
54+
std::string prefix = "__label__";
55+
if (label.find(prefix) == 0) {
56+
label = label.substr(prefix.length());
57+
}
58+
return env->NewStringUTF(label.c_str());
59+
}
60+
61+
return env->NewStringUTF("und");
62+
}
63+
64+
extern "C" JNIEXPORT void JNICALL
65+
Java_nie_translator_rtranslator_voice_1translation_neural_1networks_translation_LanguageDetector_release(JNIEnv* env, jobject /* this */, jlong ptr) {
66+
auto* ft = reinterpret_cast<fasttext::FastText*>(ptr);
67+
delete ft; // Prevent memory leaks
68+
}
Submodule fastText added at 1142dc4
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package nie.translator.rtranslator.voice_translation.neural_networks.translation;
2+
3+
import android.content.Context;
4+
import android.util.Log;
5+
6+
import androidx.annotation.NonNull;
7+
8+
import java.io.File;
9+
import java.io.IOException;
10+
import java.nio.file.Paths;
11+
12+
import ai.djl.ModelException;
13+
import ai.djl.inference.Predictor;
14+
import ai.djl.modality.Classifications;
15+
import ai.djl.repository.zoo.Criteria;
16+
import ai.djl.repository.zoo.ZooModel;
17+
import ai.djl.translate.TranslateException;
18+
import nie.translator.rtranslator.voice_translation.neural_networks.NeuralNetworkApiResult;
19+
20+
public class LanguageDetector {
21+
// Load the C++ library
22+
static {
23+
System.loadLibrary("fasttext-lib");
24+
}
25+
26+
27+
private static final String TAG = "LanguageDetector";
28+
private static final String MODEL_FILE_NAME = "fasttext.ftz";
29+
30+
private ZooModel<String, Classifications> model;
31+
private Predictor<String, Classifications> predictor;
32+
33+
private long nativePtr = 0;
34+
private Context context;
35+
36+
/**
37+
* Initializes the detector. Call this from a background thread during app startup.
38+
*/
39+
public void initialize(Context context) throws IOException, ModelException {
40+
File modelFile = new File(context.getFilesDir(), MODEL_FILE_NAME);
41+
42+
this.context = context;
43+
this.nativePtr = initFastText();
44+
45+
loadModel(nativePtr, modelFile.getAbsolutePath());
46+
}
47+
48+
/**
49+
* Predicts the language of a given text string.
50+
*/
51+
public void detectLanguage(String text, double confidenceThreshold, @NonNull DetectLanguageListener listener) {
52+
new Thread(new Runnable() {
53+
@Override
54+
public void run() {
55+
try {
56+
if (nativePtr == 0) {
57+
Log.e(TAG, "Model not initialized.");
58+
listener.onSuccess("und");
59+
}
60+
listener.onSuccess(predictLanguage(nativePtr, text));
61+
62+
} catch (Exception e) {
63+
e.printStackTrace();
64+
Log.e(TAG, "Failed to predict language", e);
65+
listener.onSuccess("und");
66+
}
67+
}
68+
}).start();
69+
}
70+
71+
public abstract static class DetectLanguageListener {
72+
public abstract void onSuccess(String languageCode);
73+
}
74+
75+
public void close() {
76+
if (nativePtr != 0) {
77+
release(nativePtr);
78+
nativePtr = 0;
79+
}
80+
}
81+
82+
83+
private native long initFastText();
84+
private native void loadModel(long ptr, String path);
85+
private native String predictLanguage(long ptr, String text, double confidenceThreshold);
86+
private native void release(long ptr);
87+
}

0 commit comments

Comments
 (0)