{"id":21458074,"url":"https://github.com/shubham0204/sentence-embeddings-android","last_synced_at":"2025-07-15T01:31:06.077Z","repository":{"id":245865094,"uuid":"819414950","full_name":"shubham0204/Sentence-Embeddings-Android","owner":"shubham0204","description":"Embeddings from sentence-transformers in Android! Supports all-MiniLM-L6-V2, bge-small-en, snowflake-arctic, model2vec models and more","archived":false,"fork":false,"pushed_at":"2025-06-15T12:49:43.000Z","size":44057,"stargazers_count":47,"open_issues_count":5,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-15T14:08:05.408Z","etag":null,"topics":["android","machine-learning","natural-language-processing","on-device-ml","onnx","onnxruntime","sentence-embeddings","sentence-transformers"],"latest_commit_sha":null,"homepage":"https://proandroiddev.com/from-python-to-android-hf-sentence-transformers-embeddings-1ecea0ce94d8","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shubham0204.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"shubham0204","custom":["https://www.paypal.me/ShubhamPanchal0204/"]}},"created_at":"2024-06-24T13:06:14.000Z","updated_at":"2025-06-15T12:49:46.000Z","dependencies_parsed_at":"2024-06-27T06:47:34.749Z","dependency_job_id":"4ff2b329-e673-470a-a8bd-9ae6687b3f46","html_url":"https://github.com/shubham0204/Sentence-Embeddings-Android","commit_stats":null,"previous_names":["shubham0204/sentence-embeddings-android"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/shubham0204/Sentence-Embeddings-Android","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham0204%2FSentence-Embeddings-Android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham0204%2FSentence-Embeddings-Android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham0204%2FSentence-Embeddings-Android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham0204%2FSentence-Embeddings-Android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shubham0204","download_url":"https://codeload.github.com/shubham0204/Sentence-Embeddings-Android/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham0204%2FSentence-Embeddings-Android/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265385743,"owners_count":23756728,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","machine-learning","natural-language-processing","on-device-ml","onnx","onnxruntime","sentence-embeddings","sentence-transformers"],"created_at":"2024-11-23T06:17:34.327Z","updated_at":"2025-07-15T01:31:06.069Z","avatar_url":"https://github.com/shubham0204.png","language":"Kotlin","funding_links":["https://github.com/sponsors/shubham0204","https://www.paypal.me/ShubhamPanchal0204/"],"categories":[],"sub_categories":[],"readme":"# Sentence Embeddings in Android\n\n\u003e An Android library that provides a port to sentence-transformers, which are used to generate\n\u003e sentence embeddings (fixed-size vectors for text/sentences)\n\n[![](https://jitpack.io/v/shubham0204/Sentence-Embeddings-Android.svg)](https://jitpack.io/#shubham0204/Sentence-Embeddings-Android)\n\n![App Demo](resources/app_demo.gif)\n\n* Read the\n  blog: [From Python To Android: HF Sentence Transformers (Embeddings)](https://proandroiddev.com/from-python-to-android-hf-sentence-transformers-embeddings-1ecea0ce94d8)\n\n## Updates\n\n### 2025-06\n\n- Add support for 16 KB page-size Android devices by [updating project NDK version to r28b](https://developer.android.com/guide/practices/page-sizes#kotlin_1)\n\n- Modify Gradle scripts of `sentence_embeddings` and `model2vec` modules to publish the AAR as a package on Maven Central\n\n### 2025-03\n\n- Move the Rust source code from the `libs` branch to the `main` branch: We now use\n  the [rust-android-plugin](https://github.com/mozilla/rust-android-gradle/issues/29) to initiate\n  `cargo build` from Gradle\n\n- Removed Git LFS: The ONNX models present in `app/src/main/assets` have been removed from the\n  repository. Instead, `app/build.gradle.kts` downloads the models and tokenizer configs from\n  HuggingFace using `download_model.sh` shell script.\n\n- Add [Model2Vec](https://huggingface.co/blog/Pringled/model2vec): Model2Vec provides static\n  sentence-embeddings through a fast-lookup\n\n- Remove Jitpack: A GitHub CI script now builds AARs for `model2vec` and `sentence_embeddings`\n  Gradle modules that can be included in other projects\n\n### 2024-08\n\n- Along with `token_ids` and `attention_mask`, the native library now also returns `token_type_ids`\n  to support additional models like the `bge-small-en-v1.5` (issue #3)\n\n## Supported Models\n\n- [`all-minilm-l6-v2`](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/tree/main)\n- [`bge-small-en-v1.5`](https://huggingface.co/BAAI/bge-small-en-v1.5)\n- [`snowflake-arctic-embed-s`](https://huggingface.co/Snowflake/snowflake-arctic-embed-s)\n\nTo add more models, refer the [Adding New Models](#adding-new-models) section.\n\n## Installation\n\n### Maven Artifacts\n\nInclude the following in your `build.gradle` script,\n\n```groovy\ndependencies {\n    // ... other packages\n    \n    // To use sentence-embeddings\n    implementation 'io.gitlab.shubham0204:sentence-embeddings:v6'\n    \n    // To also use model2vec\n    implementation 'io.gitlab.shubham0204:model2vec:v6'\n}\n```\n\n- [`sentence-embeddings` Maven package](https://central.sonatype.com/artifact/io.gitlab.shubham0204/sentence-embeddings/v6)\n- [`model2vec` Maven package](https://central.sonatype.com/artifact/io.gitlab.shubham0204/model2vec/v6)\n\n### Using the AAR from the Releases directly\n\nThe AARs for the `sentence_embeddings` and `model2vec` modules are available in\nthe [Releases](https://github.com/shubham0204/Sentence-Embeddings-Android/releases) which can be\ndownloaded. Add the AARs to the `app/libs` directory and then in `app/build.gradle.kts`,\n\n```kotlin\ndependencies {\n    // ...\n    // Add one or both of them as needed\n    implementation(file(\"libs/sentence_embeddings.aar\"))\n    implementation(file(\"libs/model2vec.aar\"))\n    // ...\n}\n```\n\n## Building the Project\n\n1. Set up Android NDK version r27c\n   ```bash\n   # Using the nttld/setup-ndk action\n   # Example manual equivalent:\n   wget https://dl.google.com/android/repository/android-ndk-r27c-linux.zip\n   unzip android-ndk-r27c-linux.zip\n   export ANDROID_NDK_HOME=/path/to/android-ndk-r27c\n   ```\n\n2. Install Rust targets for Android\n   ```bash\n   rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android\n   ```\n\n3. Build the Rust code\n   ```bash\n   ./gradlew cargoBuild --stacktrace\n   ```\n\n4. Build AAR for sentence_embeddings module\n   ```bash\n   ./gradlew :sentence_embeddings:assembleRelease --stacktrace\n   ```\n\n5. Build AAR for model2vec module\n   ```bash\n   ./gradlew :model2vec:assembleRelease --stacktrace\n   ```\n\n6. Build APK for app module\n   ```bash\n   ./gradlew :app:assembleRelease --stacktrace\n   ```\n\n7. Build APK for app-model2vec module\n   ```bash\n   ./gradlew :app-model2vec:assembleRelease --stacktrace\n   ```\n\n## Usage\n\n### API\n\nThe library provides a `SentenceEmbedding` class with `init` and `encode` suspend functions that\ninitialize the model and generate the sentence embedding respectively.\n\nThe `init` function takes two mandatory arguments, `modelBytes` and `tokenizerBytes`.\n\n```kotlin\nimport com.ml.shubham0204.sentence_embeddings.SentenceEmbedding\n\nval sentenceEmbedding = SentenceEmbedding()\n\n// Download the model and store it in the app's internal storage\n// (OR) copy the model from the assets folder (see the app module in the repo)\nval modelFile = File(filesDir, \"model.onnx\")\nval tokenizerFile = File(filesDir, \"tokenizer.json\")\nval tokenizerBytes = tokenizerFile.readBytes()\n\nCoroutineScope(Dispatchers.IO).launch {\n    sentenceEmbedding.init(\n        modelFilepath = modelFile.absolutePath,\n        tokenizerBytes = tokenizerBytes,\n        useTokenTypeIds = false,\n        outputTensorName = \"sentence_embedding\",\n        useFP16 = false,\n        useXNNPack = false\n    )\n}\n```\n\nOnce the `init` functions completes its execution, we can call the `encode` function to transform\nthe given `sentence` to an embedding,\n\n```kotlin\nCoroutineScope(Dispatchers.IO).launch {\n    val embedding: FloatArray = sentenceEmbedding.encode(\"Delhi has a population 32 million\")\n    println(\"Embedding: $embedding\")\n    println(\"Embedding size: ${embedding.size}\")\n}\n```\n\n### Compute Cosine Similarity\n\nThe embeddings are vectors whose relative similarity can be computed by measuring the cosine of the\nangle between the vectors, also termed as *cosine similarity*,\n\n\u003e [!TIP]\n\u003e Here's an\n\u003e excellent [blog](https://towardsdatascience.com/cosine-similarity-how-does-it-measure-the-similarity-maths-behind-and-usage-in-python-50ad30aad7db)\n\u003e to under cosine similarity\n\n```kotlin\nprivate fun cosineDistance(\n    x1: FloatArray,\n    x2: FloatArray\n): Float {\n    var mag1 = 0.0f\n    var mag2 = 0.0f\n    var product = 0.0f\n    for (i in x1.indices) {\n        mag1 += x1[i].pow(2)\n        mag2 += x2[i].pow(2)\n        product += x1[i] * x2[i]\n    }\n    mag1 = sqrt(mag1)\n    mag2 = sqrt(mag2)\n    return product / (mag1 * mag2)\n}\n\nCoroutineScope(Dispatchers.IO).launch {\n    val e1: FloatArray = sentenceEmbedding.encode(\"Delhi has a population 32 million\")\n    val e2: FloatArray = sentenceEmbedding.encode(\"What is the population of Delhi?\")\n    val e3: FloatArray =\n        sentenceEmbedding.encode(\"Cities with a population greater than 4 million are termed as metro cities\")\n\n    val d12 = cosineDistance(e1, e2)\n    val d13 = cosineDistance(e1, e3)\n    println(\"Similarity between e1 and e2: $d12\")\n    println(\"Similarity between e1 and e3: $d13\")\n}\n```\n\n## Adding New Models\n\nWe demonstrate how the `snowflake-arctic-embed-s` model can be added to the sample application\npresent in the `app` module.\n\n1. Download the [\n   `model.onnx`](https://huggingface.co/Snowflake/snowflake-arctic-embed-s/blob/main/onnx/model.onnx)\n   and [\n   `tokenizer.json`](https://huggingface.co/Snowflake/snowflake-arctic-embed-s/blob/main/tokenizer.json)\n   files from the HF [\n   `snowflake-arctic-embed-s`](https://huggingface.co/Snowflake/snowflake-arctic-embed-s)\n   repository.\n\n2. Create a new sub-directory in `app/src/main/assets` named `snowflake-arctic-embed-s`, the copy\n   the two files to the sub-directory.\n\n3. In `Config.kt`, add a new entry in the `Models` enum and a new branch in `getModelConfig`\n   corresponding to the new model entry added in the enum,\n\n```kotlin\nenum class Model {\n    ALL_MINILM_L6_V2,\n    BGE_SMALL_EN_V1_5,\n    SNOWFLAKE_ARCTIC_EMBED_S // Add the new entry\n}\n\nfun getModelConfig(model: Model): ModelConfig {\n    return when (model) {\n        Model.ALL_MINILM_L6_V2 -\u003e ModelConfig(\n            modelName = \"all-minilm-l6-v2\",\n            modelAssetsFilepath = \"all-minilm-l6-v2/model.onnx\",\n            tokenizerAssetsFilepath = \"all-minilm-l6-v2/tokenizer.json\",\n            useTokenTypeIds = false,\n            outputTensorName = \"sentence_embedding\"\n        )\n        Model.BGE_SMALL_EN_V1_5 -\u003e ModelConfig(\n            modelName = \"bge-small-en-v1.5\",\n            modelAssetsFilepath = \"bge-small-en-v1_5/model.onnx\",\n            tokenizerAssetsFilepath = \"bge-small-en-v1_5/tokenizer.json\",\n            useTokenTypeIds = true,\n            outputTensorName = \"last_hidden_state\"\n        )\n        // Add a new branch for the model\n        Model.SNOWFLAKE_ARCTIC_EMBED_S -\u003e ModelConfig(\n            modelName = \"snowflake-arctic-embed-s\",\n            modelAssetsFilepath = \"snowflake-arctic-embed-s/model.onnx\",\n            tokenizerAssetsFilepath = \"snowflake-arctic-embed-s/tokenizer.json\",\n            useTokenTypeIds = true,\n            outputTensorName = \"last_hidden_state\"\n        )\n    }\n}\n```\n\n4. To determine the values for `useTokenTypeIds` and `outputTensorName`, open the model\n   with [Netron](https://github.com/lutzroeder/netron) or load the model in Python with [\n   `onnxruntime`](https://github.com/microsoft/onnxruntime). We need to check the names of the input\n   and output tensors.\n\nWith Netron, check if `token_type_ids` is the name of an input tensor. Accordingly, set the value of\n`useTokenTypeIds` while creating an instance of `ModelConfig`. For `outputTensorName`, choose the\nname of the output tensor which provides the embedding. For the `snowflake-arctic-embed-s` model,\nthe name of that output tensor is `last_hidden_state`.\n\n![Model input/output tensor names in Netron](resources/netron_image.png)\n\nThe same information can be printed to the console with following Python snippet using the\n`onnxruntime` package,\n\n```python\nimport onnxruntime as ort\n\nsession = ort.InferenceSession(\"model.onnx\" )\n\nprint(\"Inputs: \")\nprint( [ t.shape for t in session.get_inputs() ] )\nprint( [ t.type for t in session.get_inputs() ] )\nprint( [ t.name for t in session.get_inputs() ] )\n\nprint(\"Outputs: \")\nprint( [ t.shape for t in session.get_outputs() ] )\nprint( [ t.type for t in session.get_outputs() ] )\nprint( [ t.name for t in session.get_outputs() ] )\n```\n\n5. Run the app on the test-device\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshubham0204%2Fsentence-embeddings-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshubham0204%2Fsentence-embeddings-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshubham0204%2Fsentence-embeddings-android/lists"}