From 228d6e23d4ee251a5f766f02536c282362d692b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Wed, 13 May 2026 16:30:12 +0200 Subject: [PATCH 01/16] feat(constants)!: switch URLs to v0.9.0 layout + add MODEL_REGISTRY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit URL refresh ----------- Every URL constant in the library now points at the restructured HF layout under `resolve/v0.9.0`. File names follow `___.pte`, files sit under per-size and per-backend directories. Affects: - modelUrls.ts: 170 URL refs rewritten to new paths. The 8da4w-typo file `lfm2_5_350m_xnnpack_8w4da.pte` is corrected to `..._8da4w.pte`. - ocr/models.ts: CRAFT detector URL + CRNN per-language URL template switch to the new `/xnnpack/crnn__xnnpack_fp32.pte` shape. - tts/models.ts: Kokoro consts re-rooted to `/xnnpack/kokoro___xnnpack_fp32.pte`. - tts/voices.ts: voices/ and phonemizer/ asset paths kept in place; only the `${VERSION_TAG}` value bumps. - versions.ts: VERSION_TAG -> resolve/v0.9.0. NEXT_VERSION_TAG collapsed into VERSION_TAG. PREVIOUS_VERSION_TAG=resolve/v0.8.0 retained for the two @deprecated Llama QLoRA aliases (LLAMA3_2_*_QLORA) that continue to resolve their v0.8.0 file. SpinQuant is the canonical quantized Llama 3.2 variant going forward. MODEL_REGISTRY -------------- Adds `constants/modelRegistry.ts` — a typed accessor grouped by capability (LLM, VLM, CLASSIFICATION, OBJECT_DETECTION, SEMANTIC_SEGMENTATION, INSTANCE_SEGMENTATION, STYLE_TRANSFER, SPEECH_TO_TEXT, TEXT_EMBEDDING, IMAGE_EMBEDDING, IMAGE_GENERATION, VAD). Each entry is callable with `{ quant, backend }`: MODEL_REGISTRY.LLM.LLAMA3_2_3B // default (base) MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true }) // SpinQuant When read as a value (object access), returns the default config; when called, resolves the requested variant. `backend` is accepted in the signature for forward-compat but the library still picks via `Platform.OS` at module load. The previous flat `MODEL_REGISTRY = { ALL_MODELS: {...} }` export in modelUrls.ts is removed; its internal-only consumer (the urlToModelName lookup) now reads from a private `_ALL_MODELS` array. Resolves the JS-API side of the HF naming convention migration. --- .../src/constants/modelRegistry.ts | 190 ++++++ .../src/constants/modelUrls.ts | 561 +++++++++--------- .../src/constants/ocr/models.ts | 6 +- .../src/constants/tts/models.ts | 16 +- .../src/constants/versions.ts | 2 + packages/react-native-executorch/src/index.ts | 1 + 6 files changed, 479 insertions(+), 297 deletions(-) create mode 100644 packages/react-native-executorch/src/constants/modelRegistry.ts diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts new file mode 100644 index 0000000000..d6836919c2 --- /dev/null +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -0,0 +1,190 @@ +import * as M from './modelUrls'; + +/** + * Backend options accepted by `MODEL_REGISTRY` accessors. The library currently + * picks a backend at module-load time based on `Platform.OS`; explicit + * `backend` selection is accepted in the signature for forward-compatibility + * but is not yet routed through to per-backend variants. + * + * @category Utils + */ +export type Backend = 'xnnpack' | 'coreml' | 'vulkan' | 'qnn'; + +/** + * Options for a `MODEL_REGISTRY` accessor call. + * + * @category Utils + */ +export type ModelOpts = { + /** Pick the quantized variant when `true`. Ignored for models with no quantized counterpart. */ + quant?: boolean; + /** Reserved for explicit per-backend selection. Today the platform-default applies. */ + backend?: Backend; +}; + +/** + * An accessor that behaves as the default model config when read as a value + * (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelName`) and as a function when + * called (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })`). + */ +type Accessor = T & ((opts?: ModelOpts) => T); + +function accessor( + defaultConfig: T, + resolve: (opts: ModelOpts) => T +): Accessor { + const fn = ((opts: ModelOpts = {}) => resolve(opts)) as Accessor; + Object.assign(fn, defaultConfig); + return fn; +} + +const base = (c: T) => accessor(c, () => c); + +function pair( + defaultC: D, + quantC: Q +): Accessor { + return accessor(defaultC, ({ quant = false } = {}) => + quant ? quantC : defaultC + ); +} + +/** + * Typed model registry grouped by capability. Each entry exposes the model's + * default config and accepts `{ quant, backend }` for per-variant selection. + * + * @example + * ```ts + * import { MODEL_REGISTRY } from 'react-native-executorch'; + * + * // Default (non-quantized, platform-default backend) + * useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B); + * + * // Quantized variant + * useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })); + * ``` + * + * @category Utils + */ +export const MODEL_REGISTRY = { + LLM: { + LLAMA3_2_1B: pair(M.LLAMA3_2_1B, M.LLAMA3_2_1B_SPINQUANT), + LLAMA3_2_3B: pair(M.LLAMA3_2_3B, M.LLAMA3_2_3B_SPINQUANT), + QWEN3_0_6B: pair(M.QWEN3_0_6B, M.QWEN3_0_6B_QUANTIZED), + QWEN3_1_7B: pair(M.QWEN3_1_7B, M.QWEN3_1_7B_QUANTIZED), + QWEN3_4B: pair(M.QWEN3_4B, M.QWEN3_4B_QUANTIZED), + QWEN3_5_0_8B: base(M.QWEN3_5_0_8B_QUANTIZED), + QWEN3_5_2B: base(M.QWEN3_5_2B_QUANTIZED), + QWEN2_5_0_5B: pair(M.QWEN2_5_0_5B, M.QWEN2_5_0_5B_QUANTIZED), + QWEN2_5_1_5B: pair(M.QWEN2_5_1_5B, M.QWEN2_5_1_5B_QUANTIZED), + QWEN2_5_3B: pair(M.QWEN2_5_3B, M.QWEN2_5_3B_QUANTIZED), + HAMMER2_1_0_5B: pair(M.HAMMER2_1_0_5B, M.HAMMER2_1_0_5B_QUANTIZED), + HAMMER2_1_1_5B: pair(M.HAMMER2_1_1_5B, M.HAMMER2_1_1_5B_QUANTIZED), + HAMMER2_1_3B: pair(M.HAMMER2_1_3B, M.HAMMER2_1_3B_QUANTIZED), + SMOLLM2_1_135M: pair(M.SMOLLM2_1_135M, M.SMOLLM2_1_135M_QUANTIZED), + SMOLLM2_1_360M: pair(M.SMOLLM2_1_360M, M.SMOLLM2_1_360M_QUANTIZED), + SMOLLM2_1_1_7B: pair(M.SMOLLM2_1_1_7B, M.SMOLLM2_1_1_7B_QUANTIZED), + PHI_4_MINI_4B: pair(M.PHI_4_MINI_4B, M.PHI_4_MINI_4B_QUANTIZED), + LFM2_5_350M: pair(M.LFM2_5_350M, M.LFM2_5_350M_QUANTIZED), + LFM2_5_1_2B_INSTRUCT: pair( + M.LFM2_5_1_2B_INSTRUCT, + M.LFM2_5_1_2B_INSTRUCT_QUANTIZED + ), + BIELIK_V3_0_1_5B: pair(M.BIELIK_V3_0_1_5B, M.BIELIK_V3_0_1_5B_QUANTIZED), + }, + VLM: { + LFM2_5_VL_1_6B: base(M.LFM2_5_VL_1_6B_QUANTIZED), + LFM2_5_VL_450M: base(M.LFM2_5_VL_450M_QUANTIZED), + }, + CLASSIFICATION: { + EFFICIENTNET_V2_S: pair(M.EFFICIENTNET_V2_S, M.EFFICIENTNET_V2_S_QUANTIZED), + PRIVACY_FILTER_OPENAI: base(M.PRIVACY_FILTER_OPENAI), + PRIVACY_FILTER_NEMOTRON: base(M.PRIVACY_FILTER_NEMOTRON), + }, + OBJECT_DETECTION: { + SSDLITE_320_MOBILENET_V3_LARGE: base(M.SSDLITE_320_MOBILENET_V3_LARGE), + RF_DETR_NANO: base(M.RF_DETR_NANO), + YOLO26N: base(M.YOLO26N), + YOLO26S: base(M.YOLO26S), + YOLO26M: base(M.YOLO26M), + YOLO26L: base(M.YOLO26L), + YOLO26X: base(M.YOLO26X), + FASTSAM_S: base(M.FASTSAM_S), + FASTSAM_X: base(M.FASTSAM_X), + }, + SEMANTIC_SEGMENTATION: { + DEEPLAB_V3_RESNET50: pair( + M.DEEPLAB_V3_RESNET50, + M.DEEPLAB_V3_RESNET50_QUANTIZED + ), + DEEPLAB_V3_RESNET101: pair( + M.DEEPLAB_V3_RESNET101, + M.DEEPLAB_V3_RESNET101_QUANTIZED + ), + DEEPLAB_V3_MOBILENET_V3_LARGE: pair( + M.DEEPLAB_V3_MOBILENET_V3_LARGE, + M.DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED + ), + LRASPP_MOBILENET_V3_LARGE: pair( + M.LRASPP_MOBILENET_V3_LARGE, + M.LRASPP_MOBILENET_V3_LARGE_QUANTIZED + ), + FCN_RESNET50: pair(M.FCN_RESNET50, M.FCN_RESNET50_QUANTIZED), + FCN_RESNET101: pair(M.FCN_RESNET101, M.FCN_RESNET101_QUANTIZED), + SELFIE_SEGMENTATION: base(M.SELFIE_SEGMENTATION), + }, + INSTANCE_SEGMENTATION: { + YOLO26N_SEG: base(M.YOLO26N_SEG), + YOLO26S_SEG: base(M.YOLO26S_SEG), + YOLO26M_SEG: base(M.YOLO26M_SEG), + YOLO26L_SEG: base(M.YOLO26L_SEG), + YOLO26X_SEG: base(M.YOLO26X_SEG), + RF_DETR_NANO_SEG: base(M.RF_DETR_NANO_SEG), + }, + STYLE_TRANSFER: { + CANDY: pair(M.STYLE_TRANSFER_CANDY, M.STYLE_TRANSFER_CANDY_QUANTIZED), + MOSAIC: pair(M.STYLE_TRANSFER_MOSAIC, M.STYLE_TRANSFER_MOSAIC_QUANTIZED), + RAIN_PRINCESS: pair( + M.STYLE_TRANSFER_RAIN_PRINCESS, + M.STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED + ), + UDNIE: pair(M.STYLE_TRANSFER_UDNIE, M.STYLE_TRANSFER_UDNIE_QUANTIZED), + }, + SPEECH_TO_TEXT: { + WHISPER_TINY_EN: pair(M.WHISPER_TINY_EN, M.WHISPER_TINY_EN_QUANTIZED), + WHISPER_BASE_EN: pair(M.WHISPER_BASE_EN, M.WHISPER_BASE_EN_QUANTIZED), + WHISPER_SMALL_EN: pair(M.WHISPER_SMALL_EN, M.WHISPER_SMALL_EN_QUANTIZED), + WHISPER_TINY: base(M.WHISPER_TINY), + WHISPER_BASE: base(M.WHISPER_BASE), + WHISPER_SMALL: base(M.WHISPER_SMALL), + }, + TEXT_EMBEDDING: { + ALL_MINILM_L6_V2: base(M.ALL_MINILM_L6_V2), + ALL_MPNET_BASE_V2: base(M.ALL_MPNET_BASE_V2), + MULTI_QA_MINILM_L6_COS_V1: base(M.MULTI_QA_MINILM_L6_COS_V1), + MULTI_QA_MPNET_BASE_DOT_V1: base(M.MULTI_QA_MPNET_BASE_DOT_V1), + DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W: base( + M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W + ), + DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML: base( + M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML + ), + PARAPHRASE_MULTILINGUAL_MINILM_L12_V2: base( + M.PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED + ), + CLIP_VIT_BASE_PATCH32_TEXT: base(M.CLIP_VIT_BASE_PATCH32_TEXT), + }, + IMAGE_EMBEDDING: { + CLIP_VIT_BASE_PATCH32_IMAGE: pair( + M.CLIP_VIT_BASE_PATCH32_IMAGE, + M.CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED + ), + }, + IMAGE_GENERATION: { + BK_SDM_TINY_VPRED_512: base(M.BK_SDM_TINY_VPRED_512), + BK_SDM_TINY_VPRED_256: base(M.BK_SDM_TINY_VPRED_256), + }, + VAD: { + FSMN_VAD: base(M.FSMN_VAD), + }, +} as const; diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index 159396add8..4e61a19342 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -3,19 +3,19 @@ import { PRIVACY_FILTER_NEMOTRON_LABELS, PRIVACY_FILTER_OPENAI_LABELS, } from './privacyFilterLabels'; -import { URL_PREFIX, PREVIOUS_VERSION_TAG, VERSION_TAG } from './versions'; +import { URL_PREFIX, VERSION_TAG, PREVIOUS_VERSION_TAG } from './versions'; // LLMs // LLAMA 3.2 -const LLAMA3_2_3B_MODEL = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/llama-3.2-3B/original/llama3_2_3B_bf16.pte`; +const LLAMA3_2_3B_MODEL = `${URL_PREFIX}-llama-3.2/${VERSION_TAG}/3b/xnnpack/llama_3_2_3b_xnnpack_bf16.pte`; const LLAMA3_2_3B_QLORA_MODEL = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/llama-3.2-3B/QLoRA/llama3_2-3B_qat_lora.pte`; -const LLAMA3_2_3B_SPINQUANT_MODEL = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/llama-3.2-3B/spinquant/llama3_2_3B_spinquant.pte`; -const LLAMA3_2_1B_MODEL = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/llama-3.2-1B/original/llama3_2_bf16.pte`; +const LLAMA3_2_3B_SPINQUANT_MODEL = `${URL_PREFIX}-llama-3.2/${VERSION_TAG}/3b/xnnpack/llama_3_2_3b_xnnpack_spinquant.pte`; +const LLAMA3_2_1B_MODEL = `${URL_PREFIX}-llama-3.2/${VERSION_TAG}/1b/xnnpack/llama_3_2_1b_xnnpack_bf16.pte`; const LLAMA3_2_1B_QLORA_MODEL = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/llama-3.2-1B/QLoRA/llama3_2_qat_lora.pte`; -const LLAMA3_2_1B_SPINQUANT_MODEL = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/llama-3.2-1B/spinquant/llama3_2_spinquant.pte`; -const LLAMA3_2_TOKENIZER = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const LLAMA3_2_TOKENIZER_CONFIG = `${URL_PREFIX}-llama-3.2/${PREVIOUS_VERSION_TAG}/tokenizer_config.json`; +const LLAMA3_2_1B_SPINQUANT_MODEL = `${URL_PREFIX}-llama-3.2/${VERSION_TAG}/1b/xnnpack/llama_3_2_1b_xnnpack_spinquant.pte`; +const LLAMA3_2_TOKENIZER = `${URL_PREFIX}-llama-3.2/${VERSION_TAG}/tokenizer.json`; +const LLAMA3_2_TOKENIZER_CONFIG = `${URL_PREFIX}-llama-3.2/${VERSION_TAG}/tokenizer_config.json`; /** * @category Models - LLM @@ -28,6 +28,10 @@ export const LLAMA3_2_3B = { } as const; /** + * @deprecated Use `LLAMA3_2_3B_SPINQUANT` instead — SpinQuant is the + * canonical quantized Llama 3.2 3B variant going forward. This alias + * still resolves the v0.8.0 file for back-compat and will be removed in + * a future major release. * @category Models - LLM */ export const LLAMA3_2_3B_QLORA = { @@ -58,6 +62,10 @@ export const LLAMA3_2_1B = { } as const; /** + * @deprecated Use `LLAMA3_2_1B_SPINQUANT` instead — SpinQuant is the + * canonical quantized Llama 3.2 1B variant going forward. This alias + * still resolves the v0.8.0 file for back-compat and will be removed in + * a future major release. * @category Models - LLM */ export const LLAMA3_2_1B_QLORA = { @@ -78,14 +86,14 @@ export const LLAMA3_2_1B_SPINQUANT = { } as const; // QWEN 3 -const QWEN3_0_6B_MODEL = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/qwen-3-0.6B/original/qwen3_0_6b_bf16.pte`; -const QWEN3_0_6B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/qwen-3-0.6B/quantized/qwen3_0_6b_8da4w.pte`; -const QWEN3_1_7B_MODEL = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/qwen-3-1.7B/original/qwen3_1_7b_bf16.pte`; -const QWEN3_1_7B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/qwen-3-1.7B/quantized/qwen3_1_7b_8da4w.pte`; -const QWEN3_4B_MODEL = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/qwen-3-4B/original/qwen3_4b_bf16.pte`; -const QWEN3_4B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/qwen-3-4B/quantized/qwen3_4b_8da4w.pte`; -const QWEN3_TOKENIZER = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const QWEN3_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3/${PREVIOUS_VERSION_TAG}/tokenizer_config.json`; +const QWEN3_0_6B_MODEL = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/0_6b/xnnpack/qwen_3_0_6b_xnnpack_bf16.pte`; +const QWEN3_0_6B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/0_6b/xnnpack/qwen_3_0_6b_xnnpack_8da4w.pte`; +const QWEN3_1_7B_MODEL = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/1_7b/xnnpack/qwen_3_1_7b_xnnpack_bf16.pte`; +const QWEN3_1_7B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/1_7b/xnnpack/qwen_3_1_7b_xnnpack_8da4w.pte`; +const QWEN3_4B_MODEL = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/4b/xnnpack/qwen_3_4b_xnnpack_bf16.pte`; +const QWEN3_4B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/4b/xnnpack/qwen_3_4b_xnnpack_8da4w.pte`; +const QWEN3_TOKENIZER = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/tokenizer.json`; +const QWEN3_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3/${VERSION_TAG}/tokenizer_config.json`; // Qwen3's published generation_config.json recommends temperature=0.6 and // top_p=0.95. We propagate those to every Qwen3 preset so model quality is @@ -162,14 +170,14 @@ export const QWEN3_4B_QUANTIZED = { } as const; // HAMMER 2.1 -const HAMMER2_1_0_5B_MODEL = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/hammer-2.1-0.5B/original/hammer2_1_0_5B_bf16.pte`; -const HAMMER2_1_0_5B_QUANTIZED_MODEL = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/hammer-2.1-0.5B/quantized/hammer2_1_0_5B_8da4w.pte`; -const HAMMER2_1_1_5B_MODEL = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/hammer-2.1-1.5B/original/hammer2_1_1_5B_bf16.pte`; -const HAMMER2_1_1_5B_QUANTIZED_MODEL = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/hammer-2.1-1.5B/quantized/hammer2_1_1_5B_8da4w.pte`; -const HAMMER2_1_3B_MODEL = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/hammer-2.1-3B/original/hammer2_1_3B_bf16.pte`; -const HAMMER2_1_3B_QUANTIZED_MODEL = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/hammer-2.1-3B/quantized/hammer2_1_3B_8da4w.pte`; -const HAMMER2_1_TOKENIZER = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const HAMMER2_1_TOKENIZER_CONFIG = `${URL_PREFIX}-hammer-2.1/${PREVIOUS_VERSION_TAG}/tokenizer_config.json`; +const HAMMER2_1_0_5B_MODEL = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/0_5b/xnnpack/hammer_2_1_0_5b_xnnpack_bf16.pte`; +const HAMMER2_1_0_5B_QUANTIZED_MODEL = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/0_5b/xnnpack/hammer_2_1_0_5b_xnnpack_8da4w.pte`; +const HAMMER2_1_1_5B_MODEL = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/1_5b/xnnpack/hammer_2_1_1_5b_xnnpack_bf16.pte`; +const HAMMER2_1_1_5B_QUANTIZED_MODEL = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/1_5b/xnnpack/hammer_2_1_1_5b_xnnpack_8da4w.pte`; +const HAMMER2_1_3B_MODEL = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/3b/xnnpack/hammer_2_1_3b_xnnpack_bf16.pte`; +const HAMMER2_1_3B_QUANTIZED_MODEL = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/3b/xnnpack/hammer_2_1_3b_xnnpack_8da4w.pte`; +const HAMMER2_1_TOKENIZER = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/tokenizer.json`; +const HAMMER2_1_TOKENIZER_CONFIG = `${URL_PREFIX}-hammer-2.1/${VERSION_TAG}/tokenizer_config.json`; /** * @category Models - LLM @@ -232,14 +240,14 @@ export const HAMMER2_1_3B_QUANTIZED = { } as const; // SMOLLM2 -const SMOLLM2_1_135M_MODEL = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/smolLm-2-135M/original/smolLm2_135M_bf16.pte`; -const SMOLLM2_1_135M_QUANTIZED_MODEL = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/smolLm-2-135M/quantized/smolLm2_135M_8da4w.pte`; -const SMOLLM2_1_360M_MODEL = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/smolLm-2-360M/original/smolLm2_360M_bf16.pte`; -const SMOLLM2_1_360M_QUANTIZED_MODEL = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/smolLm-2-360M/quantized/smolLm2_360M_8da4w.pte`; -const SMOLLM2_1_1_7B_MODEL = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/smolLm-2-1.7B/original/smolLm2_1_7B_bf16.pte`; -const SMOLLM2_1_1_7B_QUANTIZED_MODEL = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/smolLm-2-1.7B/quantized/smolLm2_1_7B_8da4w.pte`; -const SMOLLM2_1_TOKENIZER = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const SMOLLM2_1_TOKENIZER_CONFIG = `${URL_PREFIX}-smolLm-2/${PREVIOUS_VERSION_TAG}/tokenizer_config.json`; +const SMOLLM2_1_135M_MODEL = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/135m/xnnpack/smollm2_135m_xnnpack_bf16.pte`; +const SMOLLM2_1_135M_QUANTIZED_MODEL = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/135m/xnnpack/smollm2_135m_xnnpack_8da4w.pte`; +const SMOLLM2_1_360M_MODEL = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/360m/xnnpack/smollm2_360m_xnnpack_bf16.pte`; +const SMOLLM2_1_360M_QUANTIZED_MODEL = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/360m/xnnpack/smollm2_360m_xnnpack_8da4w.pte`; +const SMOLLM2_1_1_7B_MODEL = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/1_7b/xnnpack/smollm2_1_7b_xnnpack_bf16.pte`; +const SMOLLM2_1_1_7B_QUANTIZED_MODEL = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/1_7b/xnnpack/smollm2_1_7b_xnnpack_8da4w.pte`; +const SMOLLM2_1_TOKENIZER = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/tokenizer.json`; +const SMOLLM2_1_TOKENIZER_CONFIG = `${URL_PREFIX}-smolLm-2/${VERSION_TAG}/tokenizer_config.json`; /** * @category Models - LLM @@ -302,14 +310,14 @@ export const SMOLLM2_1_1_7B_QUANTIZED = { } as const; // QWEN 2.5 -const QWEN2_5_0_5B_MODEL = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/qwen-2.5-0.5B/original/qwen2_5_0_5b_bf16.pte`; -const QWEN2_5_0_5B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/qwen-2.5-0.5B/quantized/qwen2_5_0_5b_8da4w.pte`; -const QWEN2_5_1_5B_MODEL = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/qwen-2.5-1.5B/original/qwen2_5_1_5b_bf16.pte`; -const QWEN2_5_1_5B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/qwen-2.5-1.5B/quantized/qwen2_5_1_5b_8da4w.pte`; -const QWEN2_5_3B_MODEL = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/qwen-2.5-3B/original/qwen2_5_3b_bf16.pte`; -const QWEN2_5_3B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/qwen-2.5-3B/quantized/qwen2_5_3b_8da4w.pte`; -const QWEN2_5_TOKENIZER = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const QWEN2_5_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-2.5/${PREVIOUS_VERSION_TAG}/tokenizer_config.json`; +const QWEN2_5_0_5B_MODEL = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/0_5b/xnnpack/qwen_2_5_0_5b_xnnpack_bf16.pte`; +const QWEN2_5_0_5B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/0_5b/xnnpack/qwen_2_5_0_5b_xnnpack_8da4w.pte`; +const QWEN2_5_1_5B_MODEL = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/1_5b/xnnpack/qwen_2_5_1_5b_xnnpack_bf16.pte`; +const QWEN2_5_1_5B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/1_5b/xnnpack/qwen_2_5_1_5b_xnnpack_8da4w.pte`; +const QWEN2_5_3B_MODEL = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/3b/xnnpack/qwen_2_5_3b_xnnpack_bf16.pte`; +const QWEN2_5_3B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/3b/xnnpack/qwen_2_5_3b_xnnpack_8da4w.pte`; +const QWEN2_5_TOKENIZER = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/tokenizer.json`; +const QWEN2_5_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-2.5/${VERSION_TAG}/tokenizer_config.json`; /** * @category Models - LLM @@ -372,7 +380,7 @@ export const QWEN2_5_3B_QUANTIZED = { } as const; // QWEN3.5-0.8B -const QWEN3_5_0_8B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-0.8B/qwen3_5_0_8b_xnnpack_8da4w.pte`; +const QWEN3_5_0_8B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/0_8b/xnnpack/qwen_3_5_0_8b_xnnpack_8da4w.pte`; const QWEN3_5_0_8B_TOKENIZER = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-0.8B/tokenizer.json`; const QWEN3_5_0_8B_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-0.8B/tokenizer_config.json`; @@ -387,7 +395,7 @@ export const QWEN3_5_0_8B_QUANTIZED = { } as const; // QWEN3.5-2B -const QWEN3_5_2B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-2B/qwen3_5_2b_xnnpack_8da4w.pte`; +const QWEN3_5_2B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/2b/xnnpack/qwen_3_5_2b_xnnpack_8da4w.pte`; const QWEN3_5_2B_TOKENIZER = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-2B/tokenizer.json`; const QWEN3_5_2B_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-2B/tokenizer_config.json`; @@ -402,10 +410,10 @@ export const QWEN3_5_2B_QUANTIZED = { } as const; // PHI 4 -const PHI_4_MINI_4B_MODEL = `${URL_PREFIX}-phi-4-mini/${PREVIOUS_VERSION_TAG}/original/phi-4-mini_bf16.pte`; -const PHI_4_MINI_4B_QUANTIZED_MODEL = `${URL_PREFIX}-phi-4-mini/${PREVIOUS_VERSION_TAG}/quantized/phi-4-mini_8da4w.pte`; -const PHI_4_MINI_TOKENIZER = `${URL_PREFIX}-phi-4-mini/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const PHI_4_MINI_TOKENIZER_CONFIG = `${URL_PREFIX}-phi-4-mini/${PREVIOUS_VERSION_TAG}/tokenizer_config.json`; +const PHI_4_MINI_4B_MODEL = `${URL_PREFIX}-phi-4-mini/${VERSION_TAG}/xnnpack/phi_4_mini_xnnpack_bf16.pte`; +const PHI_4_MINI_4B_QUANTIZED_MODEL = `${URL_PREFIX}-phi-4-mini/${VERSION_TAG}/xnnpack/phi_4_mini_xnnpack_8da4w.pte`; +const PHI_4_MINI_TOKENIZER = `${URL_PREFIX}-phi-4-mini/${VERSION_TAG}/tokenizer.json`; +const PHI_4_MINI_TOKENIZER_CONFIG = `${URL_PREFIX}-phi-4-mini/${VERSION_TAG}/tokenizer_config.json`; /** * @category Models - LLM @@ -428,10 +436,10 @@ export const PHI_4_MINI_4B_QUANTIZED = { } as const; // LFM2.5-1.2B-Instruct -const LFM2_5_1_2B_INSTRUCT_MODEL = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-1.2B-instruct/original/lfm2_5_1_2b_fp16.pte`; -const LFM2_5_1_2B_INSTRUCT_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-1.2B-instruct/quantized/lfm2_5_1_2b_8da4w.pte`; -const LFM2_5_1_2B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-1.2B-instruct/tokenizer.json`; -const LFM2_5_1_2B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-1.2B-instruct/tokenizer_config.json`; +const LFM2_5_1_2B_INSTRUCT_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_2b/xnnpack/lfm_2_5_1_2b_xnnpack_fp16.pte`; +const LFM2_5_1_2B_INSTRUCT_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_2b/xnnpack/lfm_2_5_1_2b_xnnpack_8da4w.pte`; +const LFM2_5_1_2B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-1.2B-instruct/tokenizer.json`; +const LFM2_5_1_2B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-1.2B-instruct/tokenizer_config.json`; /** * @category Models - LLM @@ -454,10 +462,10 @@ export const LFM2_5_1_2B_INSTRUCT_QUANTIZED = { } as const; // LFM2.5-350M -const LFM2_5_350M_MODEL = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-350M/xnnpack/lfm2_5_350m_xnnpack_fp16.pte`; -const LFM2_5_350M_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-350M/xnnpack/lfm2_5_350m_xnnpack_8w4da.pte`; -const LFM2_5_350M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-350M/tokenizer.json`; -const LFM2_5_350M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-350M/tokenizer_config.json`; +const LFM2_5_350M_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/350m/xnnpack/lfm_2_5_350m_xnnpack_fp16.pte`; +const LFM2_5_350M_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/350m/xnnpack/lfm_2_5_350m_xnnpack_8da4w.pte`; +const LFM2_5_350M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-350M/tokenizer.json`; +const LFM2_5_350M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-350M/tokenizer_config.json`; /** * @category Models - LLM @@ -480,10 +488,10 @@ export const LFM2_5_350M_QUANTIZED = { } as const; // Bielik-v3.0 -const BIELIK_V3_0_1_5B_MODEL = `${URL_PREFIX}-bielik-v3.0/${PREVIOUS_VERSION_TAG}/bielik-v3.0-1.5B/original/bielik_1_5b_v3_0_instruct_xnnpack_fp16.pte`; -const BIELIK_V3_0_1_5B_QUANTIZED_MODEL = `${URL_PREFIX}-bielik-v3.0/${PREVIOUS_VERSION_TAG}/bielik-v3.0-1.5B/quantized/bielik_1_5b_v3_0_instruct_xnnpack_8da4w.pte`; -const BIELIK_V3_0_TOKENIZER = `${URL_PREFIX}-bielik-v3.0/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const BIELIK_V3_0_TOKENIZER_CONFIG = `${URL_PREFIX}-bielik-v3.0/${PREVIOUS_VERSION_TAG}/tokenizer_config.json`; +const BIELIK_V3_0_1_5B_MODEL = `${URL_PREFIX}-bielik-v3.0/${VERSION_TAG}/xnnpack/bielik_v3_0_1_5b_xnnpack_fp16.pte`; +const BIELIK_V3_0_1_5B_QUANTIZED_MODEL = `${URL_PREFIX}-bielik-v3.0/${VERSION_TAG}/xnnpack/bielik_v3_0_1_5b_xnnpack_8da4w.pte`; +const BIELIK_V3_0_TOKENIZER = `${URL_PREFIX}-bielik-v3.0/${VERSION_TAG}/tokenizer.json`; +const BIELIK_V3_0_TOKENIZER_CONFIG = `${URL_PREFIX}-bielik-v3.0/${VERSION_TAG}/tokenizer_config.json`; /** * @category Models - LLM @@ -506,14 +514,14 @@ export const BIELIK_V3_0_1_5B_QUANTIZED = { } as const; // LFM2.5-VL-1.6B -const LFM2_VL_1_6B_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-VL-1.6B/quantized/lfm2_5_vl_1_6b_8da4w_xnnpack.pte`; -const LFM2_VL_1_6B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-VL-1.6B/tokenizer.json`; -const LFM2_VL_1_6B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-VL-1.6B/tokenizer_config.json`; +const LFM2_VL_1_6B_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_6b/xnnpack/lfm_2_5_1_6b_xnnpack_8da4w.pte`; +const LFM2_VL_1_6B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-1.6B/tokenizer.json`; +const LFM2_VL_1_6B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-1.6B/tokenizer_config.json`; // LFM2.5-VL-450M -const LFM2_VL_450M_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-VL-450M/lfm2_5_vl_450m_8da4w_xnnpack.pte`; -const LFM2_VL_450M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-VL-450M/tokenizer.json`; -const LFM2_VL_450M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${PREVIOUS_VERSION_TAG}/lfm2.5-VL-450M/tokenizer_config.json`; +const LFM2_VL_450M_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/450m/xnnpack/lfm_2_5_450m_xnnpack_8da4w.pte`; +const LFM2_VL_450M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-450M/tokenizer.json`; +const LFM2_VL_450M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-450M/tokenizer_config.json`; /** * @category Models - VLM @@ -567,12 +575,12 @@ export const LFM2_VL_450M_QUANTIZED = LFM2_5_VL_450M_QUANTIZED; // Classification const EFFICIENTNET_V2_S_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-efficientnet-v2-s/${PREVIOUS_VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp32.pte` - : `${URL_PREFIX}-efficientnet-v2-s/${PREVIOUS_VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp32.pte` + : `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_fp32.pte`; const EFFICIENTNET_V2_S_QUANTIZED_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-efficientnet-v2-s/${PREVIOUS_VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp16.pte` - : `${URL_PREFIX}-efficientnet-v2-s/${PREVIOUS_VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_int8.pte`; + ? `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp16.pte` + : `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_int8.pte`; /** * @category Models - Classification @@ -593,12 +601,12 @@ export const EFFICIENTNET_V2_S_QUANTIZED = { // Object detection const SSDLITE_320_MOBILENET_V3_LARGE_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${PREVIOUS_VERSION_TAG}/coreml/ssdlite320_mobilenet_v3_large_coreml_fp16.pte` - : `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${PREVIOUS_VERSION_TAG}/xnnpack/ssdlite320_mobilenet_v3_large_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/coreml/ssdlite320_mobilenet_v3_large_coreml_fp16.pte` + : `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/xnnpack/ssdlite320_mobilenet_v3_large_xnnpack_fp32.pte`; const RF_DETR_NANO_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-rfdetr-nano-detector/${PREVIOUS_VERSION_TAG}/coreml/rfdetr_n_det_coreml_int8.pte` - : `${URL_PREFIX}-rfdetr-nano-detector/${PREVIOUS_VERSION_TAG}/rfdetr_detector.pte`; + ? `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte` + : `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`; /** * @category Models - Object Detection @@ -617,11 +625,11 @@ export const RF_DETR_NANO = { } as const; // YOLO26 Object Detection -const YOLO26N_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${PREVIOUS_VERSION_TAG}/yolo26n/xnnpack/yolo26n.pte`; -const YOLO26S_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${PREVIOUS_VERSION_TAG}/yolo26s/xnnpack/yolo26s.pte`; -const YOLO26M_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${PREVIOUS_VERSION_TAG}/yolo26m/xnnpack/yolo26m.pte`; -const YOLO26L_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${PREVIOUS_VERSION_TAG}/yolo26l/xnnpack/yolo26l.pte`; -const YOLO26X_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${PREVIOUS_VERSION_TAG}/yolo26x/xnnpack/yolo26x.pte`; +const YOLO26N_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${VERSION_TAG}/n/xnnpack/yolo26_n_xnnpack_fp32.pte`; +const YOLO26S_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${VERSION_TAG}/s/xnnpack/yolo26_s_xnnpack_fp32.pte`; +const YOLO26M_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${VERSION_TAG}/m/xnnpack/yolo26_m_xnnpack_fp32.pte`; +const YOLO26L_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${VERSION_TAG}/l/xnnpack/yolo26_l_xnnpack_fp32.pte`; +const YOLO26X_DETECTION_MODEL = `${URL_PREFIX}-yolo26/${VERSION_TAG}/x/xnnpack/yolo26_x_xnnpack_fp32.pte`; /** * @category Models - Object Detection @@ -664,7 +672,7 @@ export const YOLO26X = { } as const; // YOLO26 Pose Estimation -const YOLO26N_POSE_MODEL = `${URL_PREFIX}-yolo26-pose/${VERSION_TAG}/yolo26n/xnnpack/yolo26n-pose_xnnpack.pte`; +const YOLO26N_POSE_MODEL = `${URL_PREFIX}-yolo26-pose/${VERSION_TAG}/xnnpack/yolo26_pose_n_xnnpack_fp32.pte`; /** * @category Models - Pose Estimation @@ -677,36 +685,36 @@ export const YOLO26N_POSE = { // Style transfer const STYLE_TRANSFER_CANDY_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-candy/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_candy_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-candy/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_candy_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/coreml/style_transfer_candy_coreml_fp32.pte` + : `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/xnnpack/style_transfer_candy_xnnpack_fp32.pte`; const STYLE_TRANSFER_CANDY_QUANTIZED_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-candy/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_candy_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-candy/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_candy_xnnpack_int8.pte`; + ? `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/coreml/style_transfer_candy_coreml_fp16.pte` + : `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/xnnpack/style_transfer_candy_xnnpack_int8.pte`; const STYLE_TRANSFER_MOSAIC_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-mosaic/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_mosaic_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-mosaic/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_mosaic_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/coreml/style_transfer_mosaic_coreml_fp32.pte` + : `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/xnnpack/style_transfer_mosaic_xnnpack_fp32.pte`; const STYLE_TRANSFER_MOSAIC_QUANTIZED_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-mosaic/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_mosaic_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-mosaic/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_mosaic_xnnpack_int8.pte`; + ? `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/coreml/style_transfer_mosaic_coreml_fp16.pte` + : `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/xnnpack/style_transfer_mosaic_xnnpack_int8.pte`; const STYLE_TRANSFER_RAIN_PRINCESS_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-rain-princess/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_rain_princess_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-rain-princess/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_rain_princess_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/coreml/style_transfer_rain_princess_coreml_fp32.pte` + : `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/xnnpack/style_transfer_rain_princess_xnnpack_fp32.pte`; const STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-rain-princess/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_rain_princess_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-rain-princess/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_rain_princess_xnnpack_int8.pte`; + ? `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/coreml/style_transfer_rain_princess_coreml_fp16.pte` + : `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/xnnpack/style_transfer_rain_princess_xnnpack_int8.pte`; const STYLE_TRANSFER_UDNIE_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-udnie/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_udnie_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-udnie/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_udnie_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/coreml/style_transfer_udnie_coreml_fp32.pte` + : `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/xnnpack/style_transfer_udnie_xnnpack_fp32.pte`; const STYLE_TRANSFER_UDNIE_QUANTIZED_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-udnie/${PREVIOUS_VERSION_TAG}/coreml/style_transfer_udnie_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-udnie/${PREVIOUS_VERSION_TAG}/xnnpack/style_transfer_udnie_xnnpack_int8.pte`; + ? `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/coreml/style_transfer_udnie_coreml_fp16.pte` + : `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/xnnpack/style_transfer_udnie_xnnpack_int8.pte`; /** * @category Models - Style Transfer @@ -773,32 +781,32 @@ export const STYLE_TRANSFER_UDNIE_QUANTIZED = { } as const; // S2T -const WHISPER_TINY_EN_TOKENIZER = `${URL_PREFIX}-whisper-tiny.en/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_TINY_EN_MODEL = `${URL_PREFIX}-whisper-tiny.en/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_tiny_en_xnnpack.pte`; +const WHISPER_TINY_EN_TOKENIZER = `${URL_PREFIX}-whisper-tiny.en/${VERSION_TAG}/tokenizer.json`; +const WHISPER_TINY_EN_MODEL = `${URL_PREFIX}-whisper-tiny.en/${VERSION_TAG}/xnnpack/whisper_tiny_en_xnnpack_fp32.pte`; -const WHISPER_TINY_EN_QUANTIZED_TOKENIZER = `${URL_PREFIX}-whisper-tiny-quantized.en/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_TINY_EN_QUANTIZED_MODEL = `${URL_PREFIX}-whisper-tiny-quantized.en/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_tiny_en_quantized_xnnpack.pte`; +const WHISPER_TINY_EN_QUANTIZED_TOKENIZER = `${URL_PREFIX}-whisper-tiny.en/${VERSION_TAG}/tokenizer.json`; +const WHISPER_TINY_EN_QUANTIZED_MODEL = `${URL_PREFIX}-whisper-tiny.en/${VERSION_TAG}/xnnpack/whisper_tiny_en_xnnpack_int8.pte`; -const WHISPER_BASE_EN_TOKENIZER = `${URL_PREFIX}-whisper-base.en/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_BASE_EN_MODEL = `${URL_PREFIX}-whisper-base.en/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_base_en_xnnpack.pte`; +const WHISPER_BASE_EN_TOKENIZER = `${URL_PREFIX}-whisper-base.en/${VERSION_TAG}/tokenizer.json`; +const WHISPER_BASE_EN_MODEL = `${URL_PREFIX}-whisper-base.en/${VERSION_TAG}/xnnpack/whisper_base_en_xnnpack_fp32.pte`; -const WHISPER_BASE_EN_QUANTIZED_TOKENIZER = `${URL_PREFIX}-whisper-base-quantized.en/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_BASE_EN_QUANTIZED_MODEL = `${URL_PREFIX}-whisper-base-quantized.en/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_base_en_quantized_xnnpack.pte`; +const WHISPER_BASE_EN_QUANTIZED_TOKENIZER = `${URL_PREFIX}-whisper-base.en/${VERSION_TAG}/tokenizer.json`; +const WHISPER_BASE_EN_QUANTIZED_MODEL = `${URL_PREFIX}-whisper-base.en/${VERSION_TAG}/xnnpack/whisper_base_en_xnnpack_int8.pte`; -const WHISPER_SMALL_EN_TOKENIZER = `${URL_PREFIX}-whisper-small.en/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_SMALL_EN_MODEL = `${URL_PREFIX}-whisper-small.en/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_small_en_xnnpack.pte`; +const WHISPER_SMALL_EN_TOKENIZER = `${URL_PREFIX}-whisper-small.en/${VERSION_TAG}/tokenizer.json`; +const WHISPER_SMALL_EN_MODEL = `${URL_PREFIX}-whisper-small.en/${VERSION_TAG}/xnnpack/whisper_small_en_xnnpack_fp32.pte`; -const WHISPER_SMALL_EN_QUANTIZED_TOKENIZER = `${URL_PREFIX}-whisper-small-quantized.en/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_SMALL_EN_QUANTIZED_MODEL = `${URL_PREFIX}-whisper-small-quantized.en/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_small_en_quantized_xnnpack.pte`; +const WHISPER_SMALL_EN_QUANTIZED_TOKENIZER = `${URL_PREFIX}-whisper-small.en/${VERSION_TAG}/tokenizer.json`; +const WHISPER_SMALL_EN_QUANTIZED_MODEL = `${URL_PREFIX}-whisper-small.en/${VERSION_TAG}/xnnpack/whisper_small_en_xnnpack_int8.pte`; -const WHISPER_TINY_TOKENIZER = `${URL_PREFIX}-whisper-tiny/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_TINY_MODEL = `${URL_PREFIX}-whisper-tiny/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_tiny_xnnpack.pte`; +const WHISPER_TINY_TOKENIZER = `${URL_PREFIX}-whisper-tiny/${VERSION_TAG}/tokenizer.json`; +const WHISPER_TINY_MODEL = `${URL_PREFIX}-whisper-tiny/${VERSION_TAG}/xnnpack/whisper_tiny_xnnpack_fp32.pte`; -const WHISPER_BASE_TOKENIZER = `${URL_PREFIX}-whisper-base/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_BASE_MODEL = `${URL_PREFIX}-whisper-base/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_base_xnnpack.pte`; +const WHISPER_BASE_TOKENIZER = `${URL_PREFIX}-whisper-base/${VERSION_TAG}/tokenizer.json`; +const WHISPER_BASE_MODEL = `${URL_PREFIX}-whisper-base/${VERSION_TAG}/xnnpack/whisper_base_xnnpack_fp32.pte`; -const WHISPER_SMALL_TOKENIZER = `${URL_PREFIX}-whisper-small/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const WHISPER_SMALL_MODEL = `${URL_PREFIX}-whisper-small/${PREVIOUS_VERSION_TAG}/xnnpack/whisper_small_xnnpack.pte`; +const WHISPER_SMALL_TOKENIZER = `${URL_PREFIX}-whisper-small/${VERSION_TAG}/tokenizer.json`; +const WHISPER_SMALL_MODEL = `${URL_PREFIX}-whisper-small/${VERSION_TAG}/xnnpack/whisper_small_xnnpack_fp32.pte`; /** * @category Models - Speech To Text @@ -891,18 +899,18 @@ export const WHISPER_SMALL = { } as const; // Semantic Segmentation -const DEEPLAB_V3_RESNET50_MODEL = `${URL_PREFIX}-deeplab-v3/${PREVIOUS_VERSION_TAG}/deeplab-v3-resnet50/xnnpack/deeplabv3_resnet50_xnnpack_fp32.pte`; -const DEEPLAB_V3_RESNET101_MODEL = `${URL_PREFIX}-deeplab-v3/${PREVIOUS_VERSION_TAG}/deeplab-v3-resnet101/xnnpack/deeplabv3_resnet101_xnnpack_fp32.pte`; -const DEEPLAB_V3_MOBILENET_V3_LARGE_MODEL = `${URL_PREFIX}-deeplab-v3/${PREVIOUS_VERSION_TAG}/deeplab-v3-mobilenet-v3-large/xnnpack/deeplabv3_mobilenet_v3_large_xnnpack_fp32.pte`; -const LRASPP_MOBILENET_V3_LARGE_MODEL = `${URL_PREFIX}-lraspp/${PREVIOUS_VERSION_TAG}/xnnpack/lraspp_mobilenet_v3_large_xnnpack_fp32.pte`; -const FCN_RESNET50_MODEL = `${URL_PREFIX}-fcn/${PREVIOUS_VERSION_TAG}/fcn-resnet50/xnnpack/fcn_resnet50_xnnpack_fp32.pte`; -const FCN_RESNET101_MODEL = `${URL_PREFIX}-fcn/${PREVIOUS_VERSION_TAG}/fcn-resnet101/xnnpack/fcn_resnet101_xnnpack_fp32.pte`; -const DEEPLAB_V3_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${PREVIOUS_VERSION_TAG}/deeplab-v3-resnet50/xnnpack/deeplabv3_resnet50_xnnpack_int8.pte`; -const DEEPLAB_V3_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${PREVIOUS_VERSION_TAG}/deeplab-v3-resnet101/xnnpack/deeplabv3_resnet101_xnnpack_int8.pte`; -const DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${PREVIOUS_VERSION_TAG}/deeplab-v3-mobilenet-v3-large/xnnpack/deeplabv3_mobilenet_v3_large_xnnpack_int8.pte`; -const LRASPP_MOBILENET_V3_LARGE_QUANTIZED_MODEL = `${URL_PREFIX}-lraspp/${PREVIOUS_VERSION_TAG}/xnnpack/lraspp_mobilenet_v3_large_xnnpack_int8.pte`; -const FCN_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${PREVIOUS_VERSION_TAG}/fcn-resnet50/xnnpack/fcn_resnet50_xnnpack_int8.pte`; -const FCN_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${PREVIOUS_VERSION_TAG}/fcn-resnet101/xnnpack/fcn_resnet101_xnnpack_int8.pte`; +const DEEPLAB_V3_RESNET50_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_fp32.pte`; +const DEEPLAB_V3_RESNET101_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_fp32.pte`; +const DEEPLAB_V3_MOBILENET_V3_LARGE_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_fp32.pte`; +const LRASPP_MOBILENET_V3_LARGE_MODEL = `${URL_PREFIX}-lraspp/${VERSION_TAG}/xnnpack/lraspp_mobilenet_v3_large_xnnpack_fp32.pte`; +const FCN_RESNET50_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_fp32.pte`; +const FCN_RESNET101_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_fp32.pte`; +const DEEPLAB_V3_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_int8.pte`; +const DEEPLAB_V3_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_int8.pte`; +const DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_int8.pte`; +const LRASPP_MOBILENET_V3_LARGE_QUANTIZED_MODEL = `${URL_PREFIX}-lraspp/${VERSION_TAG}/xnnpack/lraspp_mobilenet_v3_large_xnnpack_int8.pte`; +const FCN_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_int8.pte`; +const FCN_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_int8.pte`; /** * @category Models - Semantic Segmentation @@ -1000,7 +1008,7 @@ export const FCN_RESNET101_QUANTIZED = { modelSource: FCN_RESNET101_QUANTIZED_MODEL, } as const; -const SELFIE_SEGMENTATION_MODEL = `${URL_PREFIX}-selfie-segmentation/${PREVIOUS_VERSION_TAG}/xnnpack/selfie-segmentation.pte`; +const SELFIE_SEGMENTATION_MODEL = `${URL_PREFIX}-selfie-segmentation/${VERSION_TAG}/xnnpack/selfie_segmentation_xnnpack_fp32.pte`; /** * @category Models - Semantic Segmentation @@ -1013,12 +1021,12 @@ export const SELFIE_SEGMENTATION = { // FastSAM Instance Segmentation const FASTSAM_S_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/fastsam-s/coreml/fastsam_s_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/fastsam-s/xnnpack/fastsam_s_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte` + : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`; const FASTSAM_X_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/fastsam-x/coreml/fastsam_x_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/fastsam-x/xnnpack/fastsam_x_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte` + : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`; /** * @category Models - Instance Segmentation @@ -1039,15 +1047,15 @@ export const FASTSAM_X = { /** * @category Models - Instance Segmentation */ -const YOLO26N_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${PREVIOUS_VERSION_TAG}/yolo26n-seg/xnnpack/yolo26n-seg.pte`; -const YOLO26S_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${PREVIOUS_VERSION_TAG}/yolo26s-seg/xnnpack/yolo26s-seg.pte`; -const YOLO26M_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${PREVIOUS_VERSION_TAG}/yolo26m-seg/xnnpack/yolo26m-seg.pte`; -const YOLO26L_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${PREVIOUS_VERSION_TAG}/yolo26l-seg/xnnpack/yolo26l-seg.pte`; -const YOLO26X_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${PREVIOUS_VERSION_TAG}/yolo26x-seg/xnnpack/yolo26x-seg.pte`; +const YOLO26N_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/n/xnnpack/yolo26_seg_n_xnnpack_fp32.pte`; +const YOLO26S_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/s/xnnpack/yolo26_seg_s_xnnpack_fp32.pte`; +const YOLO26M_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/m/xnnpack/yolo26_seg_m_xnnpack_fp32.pte`; +const YOLO26L_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/l/xnnpack/yolo26_seg_l_xnnpack_fp32.pte`; +const YOLO26X_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/x/xnnpack/yolo26_seg_x_xnnpack_fp32.pte`; const RF_DETR_NANO_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-rfdetr-nano-segmentation/${PREVIOUS_VERSION_TAG}/coreml/rfdetr_n_seg_coreml_int8.pte` - : `${URL_PREFIX}-rfdetr-nano-segmentation/${PREVIOUS_VERSION_TAG}/rfdetr_segmentation.pte`; + ? `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte` + : `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`; /** * @category Models - Instance Segmentation */ @@ -1097,8 +1105,8 @@ export const RF_DETR_NANO_SEG = { } as const; // Image Embeddings -const CLIP_VIT_BASE_PATCH32_IMAGE_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${PREVIOUS_VERSION_TAG}/xnnpack/clip_vit_base_patch32_vision_xnnpack_fp32.pte`; -const CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${PREVIOUS_VERSION_TAG}/xnnpack/clip_vit_base_patch32_vision_xnnpack_int8.pte`; +const CLIP_VIT_BASE_PATCH32_IMAGE_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_xnnpack_fp32.pte`; +const CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_xnnpack_int8.pte`; /** * @category Models - Image Embeddings @@ -1117,21 +1125,21 @@ export const CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED = { } as const; // Text Embeddings -const ALL_MINILM_L6_V2_MODEL = `${URL_PREFIX}-all-MiniLM-L6-v2/${PREVIOUS_VERSION_TAG}/all-MiniLM-L6-v2_xnnpack.pte`; -const ALL_MINILM_L6_V2_TOKENIZER = `${URL_PREFIX}-all-MiniLM-L6-v2/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const ALL_MPNET_BASE_V2_MODEL = `${URL_PREFIX}-all-mpnet-base-v2/${PREVIOUS_VERSION_TAG}/all-mpnet-base-v2_xnnpack.pte`; -const ALL_MPNET_BASE_V2_TOKENIZER = `${URL_PREFIX}-all-mpnet-base-v2/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const MULTI_QA_MINILM_L6_COS_V1_MODEL = `${URL_PREFIX}-multi-qa-MiniLM-L6-cos-v1/${PREVIOUS_VERSION_TAG}/multi-qa-MiniLM-L6-cos-v1_xnnpack.pte`; -const MULTI_QA_MINILM_L6_COS_V1_TOKENIZER = `${URL_PREFIX}-multi-qa-MiniLM-L6-cos-v1/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const MULTI_QA_MPNET_BASE_DOT_V1_MODEL = `${URL_PREFIX}-multi-qa-mpnet-base-dot-v1/${PREVIOUS_VERSION_TAG}/multi-qa-mpnet-base-dot-v1_xnnpack.pte`; -const MULTI_QA_MPNET_BASE_DOT_V1_TOKENIZER = `${URL_PREFIX}-multi-qa-mpnet-base-dot-v1/${PREVIOUS_VERSION_TAG}/tokenizer.json`; -const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/xnnpack/distiluse-base-multilingual-cased-v2_xnnpack_8da4w.pte`; -const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/coreml/distiluse-base-multilingual-cased-v2_coreml_fp32.pte`; +const ALL_MINILM_L6_V2_MODEL = `${URL_PREFIX}-all-MiniLM-L6-v2/${VERSION_TAG}/xnnpack/all_minilm_l6_v2_xnnpack_fp32.pte`; +const ALL_MINILM_L6_V2_TOKENIZER = `${URL_PREFIX}-all-MiniLM-L6-v2/${VERSION_TAG}/tokenizer.json`; +const ALL_MPNET_BASE_V2_MODEL = `${URL_PREFIX}-all-mpnet-base-v2/${VERSION_TAG}/xnnpack/all_mpnet_base_v2_xnnpack_fp32.pte`; +const ALL_MPNET_BASE_V2_TOKENIZER = `${URL_PREFIX}-all-mpnet-base-v2/${VERSION_TAG}/tokenizer.json`; +const MULTI_QA_MINILM_L6_COS_V1_MODEL = `${URL_PREFIX}-multi-qa-MiniLM-L6-cos-v1/${VERSION_TAG}/xnnpack/multi_qa_minilm_l6_cos_v1_xnnpack_fp32.pte`; +const MULTI_QA_MINILM_L6_COS_V1_TOKENIZER = `${URL_PREFIX}-multi-qa-MiniLM-L6-cos-v1/${VERSION_TAG}/tokenizer.json`; +const MULTI_QA_MPNET_BASE_DOT_V1_MODEL = `${URL_PREFIX}-multi-qa-mpnet-base-dot-v1/${VERSION_TAG}/xnnpack/multi_qa_mpnet_base_dot_v1_xnnpack_fp32.pte`; +const MULTI_QA_MPNET_BASE_DOT_V1_TOKENIZER = `${URL_PREFIX}-multi-qa-mpnet-base-dot-v1/${VERSION_TAG}/tokenizer.json`; +const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/xnnpack/distiluse_base_multilingual_cased_v2_xnnpack_8da4w.pte`; +const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/coreml/distiluse_base_multilingual_cased_v2_coreml_fp32.pte`; const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_TOKENIZER = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/tokenizer.json`; -const PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED_MODEL = `${URL_PREFIX}-paraphrase-multilingual-MiniLM-L12-v2/${VERSION_TAG}/xnnpack/paraphrase-multilingual-MiniLM-L12-v2_xnnpack_8da4w.pte`; +const PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED_MODEL = `${URL_PREFIX}-paraphrase-multilingual-MiniLM-L12-v2/${VERSION_TAG}/xnnpack/paraphrase_multilingual_minilm_l12_v2_xnnpack_8da4w.pte`; const PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_TOKENIZER = `${URL_PREFIX}-paraphrase-multilingual-MiniLM-L12-v2/${VERSION_TAG}/tokenizer.json`; -const CLIP_VIT_BASE_PATCH32_TEXT_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${PREVIOUS_VERSION_TAG}/xnnpack/clip_vit_base_patch32_text_xnnpack_fp32.pte`; -const CLIP_VIT_BASE_PATCH32_TEXT_TOKENIZER = `${URL_PREFIX}-clip-vit-base-patch32/${PREVIOUS_VERSION_TAG}/tokenizer.json`; +const CLIP_VIT_BASE_PATCH32_TEXT_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_xnnpack_fp32.pte`; +const CLIP_VIT_BASE_PATCH32_TEXT_TOKENIZER = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/tokenizer.json`; /** * @category Models - Text Embeddings @@ -1220,7 +1228,7 @@ export const CLIP_VIT_BASE_PATCH32_TEXT = { */ export const PRIVACY_FILTER_OPENAI = { modelName: 'privacy-filter-openai', - modelSource: `${URL_PREFIX}-privacy-filter-openai/${VERSION_TAG}/xnnpack/privacy-filter_xnnpack_8da4w.pte`, + modelSource: `${URL_PREFIX}-privacy-filter-openai/${VERSION_TAG}/xnnpack/privacy_filter_openai_xnnpack_8da4w.pte`, tokenizerSource: `${URL_PREFIX}-privacy-filter-openai/${VERSION_TAG}/tokenizer.json`, labelNames: PRIVACY_FILTER_OPENAI_LABELS, } as const; @@ -1233,7 +1241,7 @@ export const PRIVACY_FILTER_OPENAI = { */ export const PRIVACY_FILTER_NEMOTRON = { modelName: 'privacy-filter-nemotron', - modelSource: `${URL_PREFIX}-privacy-filter-nemotron/${VERSION_TAG}/xnnpack/privacy-filter-nemotron_xnnpack_8da4w.pte`, + modelSource: `${URL_PREFIX}-privacy-filter-nemotron/${VERSION_TAG}/xnnpack/privacy_filter_nemotron_xnnpack_8da4w.pte`, tokenizerSource: `${URL_PREFIX}-privacy-filter-nemotron/${VERSION_TAG}/tokenizer.json`, labelNames: PRIVACY_FILTER_NEMOTRON_LABELS, } as const; @@ -1245,11 +1253,11 @@ export const PRIVACY_FILTER_NEMOTRON = { */ export const BK_SDM_TINY_VPRED_512 = { modelName: 'bk-sdm-tiny-vpred-512', - schedulerSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/scheduler/scheduler_config.json`, - tokenizerSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/tokenizer/tokenizer.json`, - encoderSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/text_encoder/model.pte`, - unetSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/unet/model.pte`, - decoderSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/vae/model.pte`, + schedulerSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/scheduler/scheduler_config.json`, + tokenizerSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/tokenizer/tokenizer.json`, + encoderSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/xnnpack/bk_sdm_tiny_text_encoder_xnnpack_fp32.pte`, + unetSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/xnnpack/bk_sdm_tiny_unet_xnnpack_fp32.pte`, + decoderSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/xnnpack/bk_sdm_tiny_vae_xnnpack_fp32.pte`, } as const; /** @@ -1257,15 +1265,15 @@ export const BK_SDM_TINY_VPRED_512 = { */ export const BK_SDM_TINY_VPRED_256 = { modelName: 'bk-sdm-tiny-vpred-256', - schedulerSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/scheduler/scheduler_config.json`, - tokenizerSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/tokenizer/tokenizer.json`, - encoderSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/text_encoder/model.pte`, - unetSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/unet/model.256.pte`, - decoderSource: `${URL_PREFIX}-bk-sdm-tiny/${PREVIOUS_VERSION_TAG}/vae/model.256.pte`, + schedulerSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/scheduler/scheduler_config.json`, + tokenizerSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/tokenizer/tokenizer.json`, + encoderSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/xnnpack/bk_sdm_tiny_text_encoder_xnnpack_fp32.pte`, + unetSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/xnnpack/bk_sdm_tiny_unet_256_xnnpack_fp32.pte`, + decoderSource: `${URL_PREFIX}-bk-sdm-tiny/${VERSION_TAG}/xnnpack/bk_sdm_tiny_vae_256_xnnpack_fp32.pte`, } as const; // Voice Activity Detection -const FSMN_VAD_MODEL = `${URL_PREFIX}-fsmn-vad/${PREVIOUS_VERSION_TAG}/xnnpack/fsmn-vad_xnnpack.pte`; +const FSMN_VAD_MODEL = `${URL_PREFIX}-fsmn-vad/${VERSION_TAG}/xnnpack/fsmn_vad_xnnpack_fp32.pte`; /** * @category Models - Voice Activity Detection @@ -1275,131 +1283,112 @@ export const FSMN_VAD = { modelSource: FSMN_VAD_MODEL, } as const; -/** - * Registry of all available model configurations. - * - * Use this to discover and enumerate all models shipped with the library. - * @example - * ```ts - * import { MODEL_REGISTRY } from 'react-native-executorch'; - * - * // List all model names - * const names = Object.values(MODEL_REGISTRY).map(m => m.modelName); - * - * // Find models by name substring - * const whisperModels = Object.values(MODEL_REGISTRY) - * .filter(m => m.modelName.includes('whisper')); - * ``` - * @category Utils - */ -export const MODEL_REGISTRY = { - ALL_MODELS: { - LLAMA3_2_3B, - LLAMA3_2_3B_QLORA, - LLAMA3_2_3B_SPINQUANT, - LLAMA3_2_1B, - LLAMA3_2_1B_QLORA, - LLAMA3_2_1B_SPINQUANT, - QWEN3_0_6B, - QWEN3_0_6B_QUANTIZED, - QWEN3_1_7B, - QWEN3_1_7B_QUANTIZED, - QWEN3_4B, - QWEN3_4B_QUANTIZED, - QWEN3_5_0_8B_QUANTIZED, - QWEN3_5_2B_QUANTIZED, - HAMMER2_1_0_5B, - HAMMER2_1_0_5B_QUANTIZED, - HAMMER2_1_1_5B, - HAMMER2_1_1_5B_QUANTIZED, - HAMMER2_1_3B, - HAMMER2_1_3B_QUANTIZED, - SMOLLM2_1_135M, - SMOLLM2_1_135M_QUANTIZED, - SMOLLM2_1_360M, - SMOLLM2_1_360M_QUANTIZED, - SMOLLM2_1_1_7B, - SMOLLM2_1_1_7B_QUANTIZED, - QWEN2_5_0_5B, - QWEN2_5_0_5B_QUANTIZED, - QWEN2_5_1_5B, - QWEN2_5_1_5B_QUANTIZED, - QWEN2_5_3B, - QWEN2_5_3B_QUANTIZED, - PHI_4_MINI_4B, - PHI_4_MINI_4B_QUANTIZED, - LFM2_5_350M, - LFM2_5_350M_QUANTIZED, - LFM2_5_1_2B_INSTRUCT, - LFM2_5_1_2B_INSTRUCT_QUANTIZED, - LFM2_5_VL_1_6B_QUANTIZED, - LFM2_5_VL_450M_QUANTIZED, - LFM2_VL_1_6B_QUANTIZED, - LFM2_VL_450M_QUANTIZED, - BIELIK_V3_0_1_5B, - BIELIK_V3_0_1_5B_QUANTIZED, - EFFICIENTNET_V2_S, - EFFICIENTNET_V2_S_QUANTIZED, - SSDLITE_320_MOBILENET_V3_LARGE, - RF_DETR_NANO, - STYLE_TRANSFER_CANDY, - STYLE_TRANSFER_CANDY_QUANTIZED, - STYLE_TRANSFER_MOSAIC, - STYLE_TRANSFER_MOSAIC_QUANTIZED, - STYLE_TRANSFER_RAIN_PRINCESS, - STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED, - STYLE_TRANSFER_UDNIE, - STYLE_TRANSFER_UDNIE_QUANTIZED, - WHISPER_TINY_EN, - WHISPER_TINY_EN_QUANTIZED, - WHISPER_BASE_EN, - WHISPER_BASE_EN_QUANTIZED, - WHISPER_SMALL_EN, - WHISPER_SMALL_EN_QUANTIZED, - WHISPER_TINY, - WHISPER_BASE, - WHISPER_SMALL, - DEEPLAB_V3_RESNET50, - DEEPLAB_V3_RESNET101, - DEEPLAB_V3_MOBILENET_V3_LARGE, - LRASPP_MOBILENET_V3_LARGE, - FCN_RESNET50, - FCN_RESNET101, - DEEPLAB_V3_RESNET50_QUANTIZED, - DEEPLAB_V3_RESNET101_QUANTIZED, - DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED, - LRASPP_MOBILENET_V3_LARGE_QUANTIZED, - FCN_RESNET50_QUANTIZED, - FCN_RESNET101_QUANTIZED, - SELFIE_SEGMENTATION, - YOLO26N_SEG, - YOLO26S_SEG, - YOLO26M_SEG, - YOLO26L_SEG, - YOLO26X_SEG, - RF_DETR_NANO_SEG, - FASTSAM_S, - FASTSAM_X, - CLIP_VIT_BASE_PATCH32_IMAGE, - CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED, - ALL_MINILM_L6_V2, - ALL_MPNET_BASE_V2, - MULTI_QA_MINILM_L6_COS_V1, - MULTI_QA_MPNET_BASE_DOT_V1, - DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W, - DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML, - PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED, - CLIP_VIT_BASE_PATCH32_TEXT, - BK_SDM_TINY_VPRED_512, - BK_SDM_TINY_VPRED_256, - FSMN_VAD, - PRIVACY_FILTER_OPENAI, - PRIVACY_FILTER_NEMOTRON, - }, -} as const; +// Internal — populates the urlToModelName lookup below. Not exported: the +// typed grouping lives in `./modelRegistry` as MODEL_REGISTRY. +const _ALL_MODELS = [ + LLAMA3_2_3B, + LLAMA3_2_3B_QLORA, + LLAMA3_2_3B_SPINQUANT, + LLAMA3_2_1B, + LLAMA3_2_1B_QLORA, + LLAMA3_2_1B_SPINQUANT, + QWEN3_0_6B, + QWEN3_0_6B_QUANTIZED, + QWEN3_1_7B, + QWEN3_1_7B_QUANTIZED, + QWEN3_4B, + QWEN3_4B_QUANTIZED, + QWEN3_5_0_8B_QUANTIZED, + QWEN3_5_2B_QUANTIZED, + HAMMER2_1_0_5B, + HAMMER2_1_0_5B_QUANTIZED, + HAMMER2_1_1_5B, + HAMMER2_1_1_5B_QUANTIZED, + HAMMER2_1_3B, + HAMMER2_1_3B_QUANTIZED, + SMOLLM2_1_135M, + SMOLLM2_1_135M_QUANTIZED, + SMOLLM2_1_360M, + SMOLLM2_1_360M_QUANTIZED, + SMOLLM2_1_1_7B, + SMOLLM2_1_1_7B_QUANTIZED, + QWEN2_5_0_5B, + QWEN2_5_0_5B_QUANTIZED, + QWEN2_5_1_5B, + QWEN2_5_1_5B_QUANTIZED, + QWEN2_5_3B, + QWEN2_5_3B_QUANTIZED, + PHI_4_MINI_4B, + PHI_4_MINI_4B_QUANTIZED, + LFM2_5_350M, + LFM2_5_350M_QUANTIZED, + LFM2_5_1_2B_INSTRUCT, + LFM2_5_1_2B_INSTRUCT_QUANTIZED, + LFM2_5_VL_1_6B_QUANTIZED, + LFM2_5_VL_450M_QUANTIZED, + BIELIK_V3_0_1_5B, + BIELIK_V3_0_1_5B_QUANTIZED, + EFFICIENTNET_V2_S, + EFFICIENTNET_V2_S_QUANTIZED, + SSDLITE_320_MOBILENET_V3_LARGE, + RF_DETR_NANO, + STYLE_TRANSFER_CANDY, + STYLE_TRANSFER_CANDY_QUANTIZED, + STYLE_TRANSFER_MOSAIC, + STYLE_TRANSFER_MOSAIC_QUANTIZED, + STYLE_TRANSFER_RAIN_PRINCESS, + STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED, + STYLE_TRANSFER_UDNIE, + STYLE_TRANSFER_UDNIE_QUANTIZED, + WHISPER_TINY_EN, + WHISPER_TINY_EN_QUANTIZED, + WHISPER_BASE_EN, + WHISPER_BASE_EN_QUANTIZED, + WHISPER_SMALL_EN, + WHISPER_SMALL_EN_QUANTIZED, + WHISPER_TINY, + WHISPER_BASE, + WHISPER_SMALL, + DEEPLAB_V3_RESNET50, + DEEPLAB_V3_RESNET101, + DEEPLAB_V3_MOBILENET_V3_LARGE, + LRASPP_MOBILENET_V3_LARGE, + FCN_RESNET50, + FCN_RESNET101, + DEEPLAB_V3_RESNET50_QUANTIZED, + DEEPLAB_V3_RESNET101_QUANTIZED, + DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED, + LRASPP_MOBILENET_V3_LARGE_QUANTIZED, + FCN_RESNET50_QUANTIZED, + FCN_RESNET101_QUANTIZED, + SELFIE_SEGMENTATION, + YOLO26N_SEG, + YOLO26S_SEG, + YOLO26M_SEG, + YOLO26L_SEG, + YOLO26X_SEG, + RF_DETR_NANO_SEG, + FASTSAM_S, + FASTSAM_X, + CLIP_VIT_BASE_PATCH32_IMAGE, + CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED, + ALL_MINILM_L6_V2, + ALL_MPNET_BASE_V2, + MULTI_QA_MINILM_L6_COS_V1, + MULTI_QA_MPNET_BASE_DOT_V1, + DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W, + DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML, + PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED, + CLIP_VIT_BASE_PATCH32_TEXT, + BK_SDM_TINY_VPRED_512, + BK_SDM_TINY_VPRED_256, + FSMN_VAD, + PRIVACY_FILTER_OPENAI, + PRIVACY_FILTER_NEMOTRON, +]; const urlToModelName = new Map(); -for (const config of Object.values(MODEL_REGISTRY.ALL_MODELS)) { +for (const config of _ALL_MODELS) { const modelName = config.modelName; for (const [key, value] of Object.entries(config)) { if (key !== 'modelName' && typeof value === 'string') { diff --git a/packages/react-native-executorch/src/constants/ocr/models.ts b/packages/react-native-executorch/src/constants/ocr/models.ts index 990156a8bd..b906f6f12b 100644 --- a/packages/react-native-executorch/src/constants/ocr/models.ts +++ b/packages/react-native-executorch/src/constants/ocr/models.ts @@ -1,11 +1,11 @@ import { alphabets, symbols } from './symbols'; -import { URL_PREFIX, PREVIOUS_VERSION_TAG } from '../versions'; +import { URL_PREFIX, VERSION_TAG } from '../versions'; -const DETECTOR_CRAFT_MODEL = `${URL_PREFIX}-detector-craft/${PREVIOUS_VERSION_TAG}/xnnpack_quantized/xnnpack_craft_quantized.pte`; +const DETECTOR_CRAFT_MODEL = `${URL_PREFIX}-detector-craft/${VERSION_TAG}/xnnpack/craft_xnnpack_int8.pte`; const createHFRecognizerDownloadUrl = (alphabet: keyof typeof alphabets) => - `${URL_PREFIX}-recognizer-crnn.en/${PREVIOUS_VERSION_TAG}/xnnpack/${alphabet}/xnnpack_crnn_${alphabet}.pte`; + `${URL_PREFIX}-recognizer-crnn.en/${VERSION_TAG}/${alphabet}/xnnpack/crnn_${alphabet}_xnnpack_fp32.pte`; const RECOGNIZER_ENGLISH_CRNN = createHFRecognizerDownloadUrl('english'); const RECOGNIZER_LATIN_CRNN = createHFRecognizerDownloadUrl('latin'); diff --git a/packages/react-native-executorch/src/constants/tts/models.ts b/packages/react-native-executorch/src/constants/tts/models.ts index e1afd989fc..ca3089c517 100644 --- a/packages/react-native-executorch/src/constants/tts/models.ts +++ b/packages/react-native-executorch/src/constants/tts/models.ts @@ -1,9 +1,9 @@ -import { URL_PREFIX, PREVIOUS_VERSION_TAG } from '../versions'; +import { URL_PREFIX, VERSION_TAG } from '../versions'; // Text to speech (tts) - Kokoro model(s) -const KOKORO_EN_MODELS_ROOT = `${URL_PREFIX}-kokoro/${PREVIOUS_VERSION_TAG}/xnnpack`; -const KOKORO_EN_SMALL_MODELS_ROOT = `${KOKORO_EN_MODELS_ROOT}/small`; -const KOKORO_EN_MEDIUM_MODELS_ROOT = `${KOKORO_EN_MODELS_ROOT}/medium`; +const KOKORO_ROOT = `${URL_PREFIX}-kokoro/${VERSION_TAG}`; +const KOKORO_SMALL_BACKEND_ROOT = `${KOKORO_ROOT}/small/xnnpack`; +const KOKORO_MEDIUM_BACKEND_ROOT = `${KOKORO_ROOT}/medium/xnnpack`; /** * A Kokoro model instance which processes the text in batches of maximum 64 tokens. @@ -13,8 +13,8 @@ const KOKORO_EN_MEDIUM_MODELS_ROOT = `${KOKORO_EN_MODELS_ROOT}/medium`; */ export const KOKORO_SMALL = { modelName: 'kokoro-small' as const, - durationPredictorSource: `${KOKORO_EN_SMALL_MODELS_ROOT}/duration_predictor.pte`, - synthesizerSource: `${KOKORO_EN_SMALL_MODELS_ROOT}/synthesizer.pte`, + durationPredictorSource: `${KOKORO_SMALL_BACKEND_ROOT}/kokoro_small_duration_predictor_xnnpack_fp32.pte`, + synthesizerSource: `${KOKORO_SMALL_BACKEND_ROOT}/kokoro_small_synthesizer_xnnpack_fp32.pte`, }; /** @@ -23,6 +23,6 @@ export const KOKORO_SMALL = { */ export const KOKORO_MEDIUM = { modelName: 'kokoro-medium' as const, - durationPredictorSource: `${KOKORO_EN_MEDIUM_MODELS_ROOT}/duration_predictor.pte`, - synthesizerSource: `${KOKORO_EN_MEDIUM_MODELS_ROOT}/synthesizer.pte`, + durationPredictorSource: `${KOKORO_MEDIUM_BACKEND_ROOT}/kokoro_medium_duration_predictor_xnnpack_fp32.pte`, + synthesizerSource: `${KOKORO_MEDIUM_BACKEND_ROOT}/kokoro_medium_synthesizer_xnnpack_fp32.pte`, }; diff --git a/packages/react-native-executorch/src/constants/versions.ts b/packages/react-native-executorch/src/constants/versions.ts index 9ce8a726d8..c272d992fe 100644 --- a/packages/react-native-executorch/src/constants/versions.ts +++ b/packages/react-native-executorch/src/constants/versions.ts @@ -2,5 +2,7 @@ export const LIB_VERSION = '0.9.0'; export const URL_PREFIX = 'https://huggingface.co/software-mansion/react-native-executorch'; +// Used by @deprecated constants that still resolve v0.8.0 files (e.g. the +// Llama QLoRA aliases superseded by SpinQuant). export const PREVIOUS_VERSION_TAG = 'resolve/v0.8.0'; export const VERSION_TAG = `resolve/v${LIB_VERSION}`; diff --git a/packages/react-native-executorch/src/index.ts b/packages/react-native-executorch/src/index.ts index 84d6da5150..6f54dbc02d 100644 --- a/packages/react-native-executorch/src/index.ts +++ b/packages/react-native-executorch/src/index.ts @@ -238,6 +238,7 @@ export * from './types/poseEstimation'; export * from './constants/commonVision'; export * from './constants/classification'; export * from './constants/modelUrls'; +export * from './constants/modelRegistry'; export * from './constants/ocr/models'; export * from './constants/tts/models'; export * from './constants/tts/voices'; From b4140307d7ee623954a9317e1f05102635f8fe70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Wed, 13 May 2026 16:47:52 +0200 Subject: [PATCH 02/16] fix(constants): split lfm-2.5 text/VL paths + colocate tokenizers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The umbrella lfm-2.5 HF repo hosts two distinct models — the text LLM (1.2B + 350M) and the vision-language model (1.6B + 450M). The migrator collapsed the VL size tokens (`vl_1_6b`, `vl_450m`) to bare numeric sizes, making VL 1.6B indistinguishable from a hypothetical text 1.6B variant. It also left the four per-variant tokenizers at their legacy `lfm2.5-*/` paths instead of moving them next to the new backend dirs. HF state (separate commits on the repo): - VL .pte files renamed to `vl_/xnnpack/lfm_2_5_vl__*.pte` - tokenizers moved into `/` and `vl_/` next to each cell - legacy `lfm2.5-*-instruct/` and `lfm2.5-VL-*/` dirs cleaned out - config.json files refreshed (vl_* configs now carry `model: lfm_2_5_vl` + `capabilities: [vision, text-generation]`) This commit refreshes the matching URL constants in modelUrls.ts so every LFM2.5 model points at its new HF path. --- .../src/constants/modelUrls.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index 4e61a19342..e82f764d36 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -438,8 +438,8 @@ export const PHI_4_MINI_4B_QUANTIZED = { // LFM2.5-1.2B-Instruct const LFM2_5_1_2B_INSTRUCT_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_2b/xnnpack/lfm_2_5_1_2b_xnnpack_fp16.pte`; const LFM2_5_1_2B_INSTRUCT_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_2b/xnnpack/lfm_2_5_1_2b_xnnpack_8da4w.pte`; -const LFM2_5_1_2B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-1.2B-instruct/tokenizer.json`; -const LFM2_5_1_2B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-1.2B-instruct/tokenizer_config.json`; +const LFM2_5_1_2B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_2b/tokenizer.json`; +const LFM2_5_1_2B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_2b/tokenizer_config.json`; /** * @category Models - LLM @@ -464,8 +464,8 @@ export const LFM2_5_1_2B_INSTRUCT_QUANTIZED = { // LFM2.5-350M const LFM2_5_350M_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/350m/xnnpack/lfm_2_5_350m_xnnpack_fp16.pte`; const LFM2_5_350M_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/350m/xnnpack/lfm_2_5_350m_xnnpack_8da4w.pte`; -const LFM2_5_350M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-350M/tokenizer.json`; -const LFM2_5_350M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-350M/tokenizer_config.json`; +const LFM2_5_350M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/350m/tokenizer.json`; +const LFM2_5_350M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/350m/tokenizer_config.json`; /** * @category Models - LLM @@ -514,14 +514,14 @@ export const BIELIK_V3_0_1_5B_QUANTIZED = { } as const; // LFM2.5-VL-1.6B -const LFM2_VL_1_6B_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/1_6b/xnnpack/lfm_2_5_1_6b_xnnpack_8da4w.pte`; -const LFM2_VL_1_6B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-1.6B/tokenizer.json`; -const LFM2_VL_1_6B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-1.6B/tokenizer_config.json`; +const LFM2_VL_1_6B_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/vl_1_6b/xnnpack/lfm_2_5_vl_1_6b_xnnpack_8da4w.pte`; +const LFM2_VL_1_6B_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/vl_1_6b/tokenizer.json`; +const LFM2_VL_1_6B_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/vl_1_6b/tokenizer_config.json`; // LFM2.5-VL-450M -const LFM2_VL_450M_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/450m/xnnpack/lfm_2_5_450m_xnnpack_8da4w.pte`; -const LFM2_VL_450M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-450M/tokenizer.json`; -const LFM2_VL_450M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/lfm2.5-VL-450M/tokenizer_config.json`; +const LFM2_VL_450M_QUANTIZED_MODEL = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/vl_450m/xnnpack/lfm_2_5_vl_450m_xnnpack_8da4w.pte`; +const LFM2_VL_450M_TOKENIZER = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/vl_450m/tokenizer.json`; +const LFM2_VL_450M_TOKENIZER_CONFIG = `${URL_PREFIX}-lfm-2.5/${VERSION_TAG}/vl_450m/tokenizer_config.json`; /** * @category Models - VLM From e994cb0d11ae979d2be52f1e7e6079191eaa76cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Wed, 13 May 2026 16:53:08 +0200 Subject: [PATCH 03/16] docs(utilities): rewrite Model Registry page for the typed accessor Covers the new grouped MODEL_REGISTRY shape (capability groups with callable accessors), the `{ quant, backend }` options, default vs quantized resolution, the still-supported direct-import pattern, and a short migration note from the previous flat `ALL_MODELS` dict. --- docs/docs/05-utilities/model-registry.md | 103 +++++++++++++++++++---- 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/docs/docs/05-utilities/model-registry.md b/docs/docs/05-utilities/model-registry.md index 02a74bbb13..2d29966ade 100644 --- a/docs/docs/05-utilities/model-registry.md +++ b/docs/docs/05-utilities/model-registry.md @@ -2,36 +2,109 @@ title: Model Registry --- -The [Model Registry](/react-native-executorch/docs/next/api-reference/variables/MODEL_REGISTRY) is a collection of all pre-configured model definitions shipped with React Native ExecuTorch. Each entry contains the model's name and all source URLs needed to download and run it, so you don't have to manage URLs manually. +The [Model Registry](/react-native-executorch/docs/next/api-reference/variables/MODEL_REGISTRY) is a typed, grouped index of every model shipped with React Native ExecuTorch. It removes the need to memorize per-model constant names: pick a capability group, pick a model, and optionally request its quantized variant. -## Usage +```typescript +import { MODEL_REGISTRY } from 'react-native-executorch'; + +// Default (non-quantized, platform-default backend). +const llm = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B); + +// Quantized variant. +const llmQuant = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })); +``` + +## Shape + +`MODEL_REGISTRY` is grouped by capability. Each leaf is callable with `{ quant, backend }` and also behaves as a plain config object when read directly. + +| Group | Examples | +| ----------------------- | ------------------------------------------------------------------------------------------------------------- | +| `LLM` | `LLAMA3_2_3B`, `QWEN3_4B`, `SMOLLM2_1_1_7B`, `PHI_4_MINI_4B`, `BIELIK_V3_0_1_5B`, `LFM2_5_1_2B_INSTRUCT`, ... | +| `VLM` | `LFM2_5_VL_1_6B`, `LFM2_5_VL_450M` | +| `CLASSIFICATION` | `EFFICIENTNET_V2_S`, `PRIVACY_FILTER_OPENAI`, `PRIVACY_FILTER_NEMOTRON` | +| `OBJECT_DETECTION` | `SSDLITE_320_MOBILENET_V3_LARGE`, `YOLO26N` … `YOLO26X`, `RF_DETR_NANO`, `FASTSAM_S`, `FASTSAM_X` | +| `SEMANTIC_SEGMENTATION` | `DEEPLAB_V3_RESNET50`, `LRASPP_MOBILENET_V3_LARGE`, `FCN_RESNET101`, `SELFIE_SEGMENTATION`, ... | +| `INSTANCE_SEGMENTATION` | `YOLO26N_SEG` … `YOLO26X_SEG`, `RF_DETR_NANO_SEG` | +| `STYLE_TRANSFER` | `CANDY`, `MOSAIC`, `RAIN_PRINCESS`, `UDNIE` | +| `SPEECH_TO_TEXT` | `WHISPER_TINY_EN`, `WHISPER_BASE`, `WHISPER_SMALL_EN`, ... | +| `TEXT_EMBEDDING` | `ALL_MINILM_L6_V2`, `ALL_MPNET_BASE_V2`, `CLIP_VIT_BASE_PATCH32_TEXT`, ... | +| `IMAGE_EMBEDDING` | `CLIP_VIT_BASE_PATCH32_IMAGE` | +| `IMAGE_GENERATION` | `BK_SDM_TINY_VPRED_256`, `BK_SDM_TINY_VPRED_512` | +| `VAD` | `FSMN_VAD` | + +## Options + +```typescript +type ModelOpts = { + quant?: boolean; // Pick the quantized variant when true. Ignored when no quantized variant exists. + backend?: 'xnnpack' | 'coreml' | 'vulkan' | 'qnn'; // Reserved; today the platform default applies. +}; +``` + +- `quant: true` resolves to the quantized variant for models that publish one (e.g. `LLAMA3_2_3B` → SpinQuant, `EFFICIENTNET_V2_S` → int8). For models with a single variant, `quant` is accepted but has no effect. +- `backend` is accepted in the signature for forward-compatibility. Today every accessor returns a config whose backend is selected at module-load time by `Platform.OS`. Explicit per-backend selection is planned for a future release. + +## Usage patterns + +### Default model + +```typescript +import { MODEL_REGISTRY } from 'react-native-executorch'; + +const llm = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B); +const classifier = useClassification( + MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S +); +const speechToText = useSpeechToText( + MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN +); +``` + +### Quantized variant ```typescript -import { MODEL_REGISTRY, LFM2_5_1_2B_INSTRUCT } from 'react-native-executorch'; +const llm = useLLM(MODEL_REGISTRY.LLM.QWEN3_4B({ quant: true })); +const classifier = useClassification( + MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: true }) +); ``` -### Accessing a model directly +### Inspecting a model's config -Every model config is exported as a standalone constant: +Accessors transparently expose the default config's fields, so you can read them without calling: ```typescript -import { LFM2_5_1_2B_INSTRUCT } from 'react-native-executorch'; +console.log(MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelName); +// → "llama-3.2-3b" -const llm = useLLM({ model: LFM2_5_1_2B_INSTRUCT }); +console.log(MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelSource); +// → "https://huggingface.co/software-mansion/react-native-executorch-llama-3.2/resolve/v0.9.0/3b/xnnpack/llama_3_2_3b_xnnpack_bf16.pte" ``` -### Listing all models +### Direct imports still work -Use `MODEL_REGISTRY` to discover and enumerate all available models: +Every model is also exported as a top-level constant. Either style is supported: ```typescript -import { MODEL_REGISTRY } from 'react-native-executorch'; +import { LFM2_5_1_2B_INSTRUCT, MODEL_REGISTRY } from 'react-native-executorch'; + +useLLM(LFM2_5_1_2B_INSTRUCT); +useLLM(MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT); +``` + +## Migration from the previous registry -// Get all model names +Earlier releases exposed `MODEL_REGISTRY.ALL_MODELS` as a flat dictionary of every model. That shape has been replaced with the grouped accessor above. + +```typescript +// Before const names = Object.values(MODEL_REGISTRY.ALL_MODELS).map((m) => m.modelName); -// Find models by name -const whisperModels = Object.values(MODEL_REGISTRY.ALL_MODELS).filter((m) => - m.modelName.includes('whisper') -); +// After +const names = Object.values(MODEL_REGISTRY) + .flatMap((group) => Object.values(group)) + .map((m) => m.modelName); ``` + +Individual constant imports (`LLAMA3_2_3B`, `WHISPER_TINY_EN`, ...) are unchanged. From 61e25a6ce6a4cc97578a919a73348d4fec7b3e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Wed, 13 May 2026 17:09:50 +0200 Subject: [PATCH 04/16] refactor(apps): migrate example apps to MODEL_REGISTRY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 22 files updated across apps/llm, apps/computer-vision, apps/speech, apps/text-embeddings, and apps/bare-rn. Each flat model-constant import is replaced with the corresponding `MODEL_REGISTRY..` (or `(...)({ quant: true })` for quantized variants). Llama QLoRA aliases remain imported under their flat names — they're deprecated and not part of the registry. Net effect: -242 / +158 lines (collapsed imports, terser callsites). Apps now serve as the canonical usage example for the typed registry. --- apps/bare-rn/App.tsx | 6 +- .../app/classification/index.tsx | 17 +- .../app/instance_segmentation/index.tsx | 32 ++-- .../app/object_detection/index.tsx | 32 ++-- .../app/segment_anything/index.tsx | 21 ++- .../app/semantic_segmentation/index.tsx | 52 ++++-- .../app/style_transfer/index.tsx | 27 ++- .../app/text_to_image/index.tsx | 15 +- .../tasks/ClassificationTask.tsx | 6 +- .../tasks/InstanceSegmentationTask.tsx | 13 +- .../tasks/ObjectDetectionTask.tsx | 10 +- .../vision_camera/tasks/SegmentationTask.tsx | 30 ++-- .../vision_camera/tasks/StyleTransferTask.tsx | 10 +- apps/llm/app/llm/index.tsx | 4 +- apps/llm/app/llm_structured_output/index.tsx | 7 +- apps/llm/app/llm_tool_calling/index.tsx | 4 +- apps/llm/app/multimodal_llm/index.tsx | 4 +- apps/llm/app/voice_chat/index.tsx | 50 ++++-- apps/llm/components/llmModels.ts | 169 ++++++++++-------- apps/speech/screens/SpeechToTextScreen.tsx | 30 ++-- .../app/clip-embeddings/index.tsx | 26 ++- .../app/text-embeddings/index.tsx | 38 ++-- 22 files changed, 353 insertions(+), 250 deletions(-) diff --git a/apps/bare-rn/App.tsx b/apps/bare-rn/App.tsx index b7e28658dc..116ddf87f5 100644 --- a/apps/bare-rn/App.tsx +++ b/apps/bare-rn/App.tsx @@ -14,9 +14,9 @@ import { View, } from 'react-native'; import { + MODEL_REGISTRY, initExecutorch, useLLM, - LLAMA3_2_1B_SPINQUANT, } from 'react-native-executorch'; import { BareResourceFetcher } from 'react-native-executorch-bare-resource-fetcher'; import { setConfig } from '@kesha-antonov/react-native-background-downloader'; @@ -144,7 +144,9 @@ function App() { const textInputRef = useRef(null); const scrollViewRef = useRef(null); - const llm = useLLM({ model: LLAMA3_2_1B_SPINQUANT }); + const llm = useLLM({ + model: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }), + }); // Alternatively, to use a custom local model, uncomment below: // const llm = useLLM({ model: { // modelSource: require('./assets/ai-models/smolLm2/smolLm2_135M/smolLm2_135M_bf16.pte'), diff --git a/apps/computer-vision/app/classification/index.tsx b/apps/computer-vision/app/classification/index.tsx index d45e0ddbf8..96c571376f 100644 --- a/apps/computer-vision/app/classification/index.tsx +++ b/apps/computer-vision/app/classification/index.tsx @@ -1,16 +1,21 @@ import Spinner from '../../components/Spinner'; import { getImage } from '../../utils'; import { + MODEL_REGISTRY, useClassification, - EFFICIENTNET_V2_S, - EFFICIENTNET_V2_S_QUANTIZED, ClassificationModelSources, } from 'react-native-executorch'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; const MODELS: ModelOption[] = [ - { label: 'EfficientNet V2 S Quantized', value: EFFICIENTNET_V2_S_QUANTIZED }, - { label: 'EfficientNet V2 S', value: EFFICIENTNET_V2_S }, + { + label: 'EfficientNet V2 S Quantized', + value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: true }), + }, + { + label: 'EfficientNet V2 S', + value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S, + }, ]; import { View, StyleSheet, Image, Text, ScrollView } from 'react-native'; import { BottomBar } from '../../components/BottomBar'; @@ -22,7 +27,9 @@ import ErrorBanner from '../../components/ErrorBanner'; export default function ClassificationScreen() { const [selectedModel, setSelectedModel] = - useState(EFFICIENTNET_V2_S_QUANTIZED); + useState( + MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: true }) + ); const [results, setResults] = useState<{ label: string; score: number }[]>( [] ); diff --git a/apps/computer-vision/app/instance_segmentation/index.tsx b/apps/computer-vision/app/instance_segmentation/index.tsx index f669c383d5..6a7a98baf0 100644 --- a/apps/computer-vision/app/instance_segmentation/index.tsx +++ b/apps/computer-vision/app/instance_segmentation/index.tsx @@ -3,16 +3,9 @@ import { BottomBar } from '../../components/BottomBar'; import { getImage } from '../../utils'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { + MODEL_REGISTRY, useInstanceSegmentation, - YOLO26N_SEG, - YOLO26S_SEG, - YOLO26M_SEG, - YOLO26L_SEG, - YOLO26X_SEG, - RF_DETR_NANO_SEG, InstanceSegmentationModelSources, - FASTSAM_S, - FASTSAM_X, } from 'react-native-executorch'; import { View, @@ -31,19 +24,24 @@ import ImageWithMasks, { import { StatsBar } from '../../components/StatsBar'; const MODELS: ModelOption[] = [ - { label: 'Yolo26N', value: YOLO26N_SEG }, - { label: 'Yolo26S', value: YOLO26S_SEG }, - { label: 'Yolo26M', value: YOLO26M_SEG }, - { label: 'Yolo26L', value: YOLO26L_SEG }, - { label: 'Yolo26X', value: YOLO26X_SEG }, - { label: 'RF-DeTR Nano', value: RF_DETR_NANO_SEG }, - { label: 'FastSAM-S', value: FASTSAM_S }, - { label: 'FastSAM-X', value: FASTSAM_X }, + { label: 'Yolo26N', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26N_SEG }, + { label: 'Yolo26S', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26S_SEG }, + { label: 'Yolo26M', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26M_SEG }, + { label: 'Yolo26L', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26L_SEG }, + { label: 'Yolo26X', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26X_SEG }, + { + label: 'RF-DeTR Nano', + value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.RF_DETR_NANO_SEG, + }, + { label: 'FastSAM-S', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_S }, + { label: 'FastSAM-X', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_X }, ]; export default function InstanceSegmentationScreen() { const [selectedModel, setSelectedModel] = - useState(YOLO26N_SEG); + useState( + MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26N_SEG + ); const [inferenceTime, setInferenceTime] = useState(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/computer-vision/app/object_detection/index.tsx b/apps/computer-vision/app/object_detection/index.tsx index ea4a9fc7b7..a369f1d9aa 100644 --- a/apps/computer-vision/app/object_detection/index.tsx +++ b/apps/computer-vision/app/object_detection/index.tsx @@ -3,15 +3,9 @@ import { BottomBar } from '../../components/BottomBar'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { getImage } from '../../utils'; import { + MODEL_REGISTRY, Detection, useObjectDetection, - RF_DETR_NANO, - SSDLITE_320_MOBILENET_V3_LARGE, - YOLO26N, - YOLO26S, - YOLO26M, - YOLO26L, - YOLO26X, ObjectDetectionModelSources, } from 'react-native-executorch'; import { View, StyleSheet, Image, Text } from 'react-native'; @@ -22,13 +16,19 @@ import ScreenWrapper from '../../ScreenWrapper'; import { StatsBar } from '../../components/StatsBar'; const MODELS: ModelOption[] = [ - { label: 'RF-DeTR Nano', value: RF_DETR_NANO }, - { label: 'SSDLite MobileNet', value: SSDLITE_320_MOBILENET_V3_LARGE }, - { label: 'YOLO26N', value: YOLO26N }, - { label: 'YOLO26S', value: YOLO26S }, - { label: 'YOLO26M', value: YOLO26M }, - { label: 'YOLO26L', value: YOLO26L }, - { label: 'YOLO26X', value: YOLO26X }, + { + label: 'RF-DeTR Nano', + value: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO, + }, + { + label: 'SSDLite MobileNet', + value: MODEL_REGISTRY.OBJECT_DETECTION.SSDLITE_320_MOBILENET_V3_LARGE, + }, + { label: 'YOLO26N', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26N }, + { label: 'YOLO26S', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26S }, + { label: 'YOLO26M', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26M }, + { label: 'YOLO26L', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26L }, + { label: 'YOLO26X', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26X }, ]; import ErrorBanner from '../../components/ErrorBanner'; @@ -41,7 +41,9 @@ export default function ObjectDetectionScreen() { height: number; }>(); const [selectedModel, setSelectedModel] = - useState(RF_DETR_NANO); + useState( + MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO + ); const [inferenceTime, setInferenceTime] = useState(null); const model = useObjectDetection({ model: selectedModel }); diff --git a/apps/computer-vision/app/segment_anything/index.tsx b/apps/computer-vision/app/segment_anything/index.tsx index 037a988327..48c36e3feb 100644 --- a/apps/computer-vision/app/segment_anything/index.tsx +++ b/apps/computer-vision/app/segment_anything/index.tsx @@ -21,13 +21,10 @@ import { AlphaType, } from '@shopify/react-native-skia'; import { + MODEL_REGISTRY, useInstanceSegmentation, useImageEmbeddings, useTextEmbeddings, - FASTSAM_S, - FASTSAM_X, - CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED, - CLIP_VIT_BASE_PATCH32_TEXT, InstanceSegmentationModelSources, SegmentedInstance, FastSAMLabel, @@ -52,15 +49,17 @@ import ColorPalette from '../../colors'; type PromptMode = 'point' | 'box' | 'text'; const MODELS: ModelOption[] = [ - { label: 'FastSAM-S', value: FASTSAM_S }, - { label: 'FastSAM-X', value: FASTSAM_X }, + { label: 'FastSAM-S', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_S }, + { label: 'FastSAM-X', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_X }, ]; export default function SegmentAnythingScreen() { const { setGlobalGenerating } = useContext(GeneratingContext); const [selectedModel, setSelectedModel] = - useState(FASTSAM_S); + useState( + MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_S + ); const [mode, setMode] = useState('point'); const [inferenceTime, setInferenceTime] = useState(null); @@ -78,9 +77,13 @@ export default function SegmentAnythingScreen() { useInstanceSegmentation({ model: selectedModel }); const clipImage = useImageEmbeddings({ - model: CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED, + model: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ + quant: true, + }), + }); + const clipText = useTextEmbeddings({ + model: MODEL_REGISTRY.TEXT_EMBEDDING.CLIP_VIT_BASE_PATCH32_TEXT, }); - const clipText = useTextEmbeddings({ model: CLIP_VIT_BASE_PATCH32_TEXT }); const skiaSource = useImage(imageUri || null); const [textPrompt, setTextPrompt] = useState(''); diff --git a/apps/computer-vision/app/semantic_segmentation/index.tsx b/apps/computer-vision/app/semantic_segmentation/index.tsx index ba998bca2a..cbbbdd2fb2 100644 --- a/apps/computer-vision/app/semantic_segmentation/index.tsx +++ b/apps/computer-vision/app/semantic_segmentation/index.tsx @@ -3,13 +3,7 @@ import { BottomBar } from '../../components/BottomBar'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { getImage } from '../../utils'; import { - DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED, - DEEPLAB_V3_RESNET50_QUANTIZED, - DEEPLAB_V3_RESNET101_QUANTIZED, - LRASPP_MOBILENET_V3_LARGE_QUANTIZED, - FCN_RESNET50_QUANTIZED, - FCN_RESNET101_QUANTIZED, - SELFIE_SEGMENTATION, + MODEL_REGISTRY, useSemanticSegmentation, SemanticSegmentationModelSources, } from 'react-native-executorch'; @@ -55,21 +49,49 @@ const numberToColor: number[][] = [ const MODELS: ModelOption[] = [ { label: 'DeepLab MobileNet', - value: DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED, + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE({ + quant: true, + }), + }, + { + label: 'DeepLab ResNet50', + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET50({ + quant: true, + }), + }, + { + label: 'DeepLab ResNet101', + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET101({ + quant: true, + }), + }, + { + label: 'LRASPP MobileNet', + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.LRASPP_MOBILENET_V3_LARGE({ + quant: true, + }), + }, + { + label: 'FCN ResNet50', + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET50({ quant: true }), + }, + { + label: 'FCN ResNet101', + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET101({ quant: true }), + }, + { + label: 'Selfie Segmentation', + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.SELFIE_SEGMENTATION, }, - { label: 'DeepLab ResNet50', value: DEEPLAB_V3_RESNET50_QUANTIZED }, - { label: 'DeepLab ResNet101', value: DEEPLAB_V3_RESNET101_QUANTIZED }, - { label: 'LRASPP MobileNet', value: LRASPP_MOBILENET_V3_LARGE_QUANTIZED }, - { label: 'FCN ResNet50', value: FCN_RESNET50_QUANTIZED }, - { label: 'FCN ResNet101', value: FCN_RESNET101_QUANTIZED }, - { label: 'Selfie Segmentation', value: SELFIE_SEGMENTATION }, ]; export default function SemanticSegmentationScreen() { const { setGlobalGenerating } = useContext(GeneratingContext); const [selectedModel, setSelectedModel] = useState( - DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED + MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE({ + quant: true, + }) ); const { diff --git a/apps/computer-vision/app/style_transfer/index.tsx b/apps/computer-vision/app/style_transfer/index.tsx index 8770087067..aac93360cf 100644 --- a/apps/computer-vision/app/style_transfer/index.tsx +++ b/apps/computer-vision/app/style_transfer/index.tsx @@ -3,11 +3,8 @@ import { BottomBar } from '../../components/BottomBar'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { getImage } from '../../utils'; import { + MODEL_REGISTRY, useStyleTransfer, - STYLE_TRANSFER_CANDY_QUANTIZED, - STYLE_TRANSFER_MOSAIC_QUANTIZED, - STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED, - STYLE_TRANSFER_UDNIE_QUANTIZED, StyleTransferModelName, ResourceSource, } from 'react-native-executorch'; @@ -25,16 +22,28 @@ type StyleTransferModelSources = { }; const MODELS: ModelOption[] = [ - { label: 'Candy', value: STYLE_TRANSFER_CANDY_QUANTIZED }, - { label: 'Mosaic', value: STYLE_TRANSFER_MOSAIC_QUANTIZED }, - { label: 'Rain Princess', value: STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED }, - { label: 'Udnie', value: STYLE_TRANSFER_UDNIE_QUANTIZED }, + { + label: 'Candy', + value: MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ quant: true }), + }, + { + label: 'Mosaic', + value: MODEL_REGISTRY.STYLE_TRANSFER.MOSAIC({ quant: true }), + }, + { + label: 'Rain Princess', + value: MODEL_REGISTRY.STYLE_TRANSFER.RAIN_PRINCESS({ quant: true }), + }, + { + label: 'Udnie', + value: MODEL_REGISTRY.STYLE_TRANSFER.UDNIE({ quant: true }), + }, ]; import ErrorBanner from '../../components/ErrorBanner'; export default function StyleTransferScreen() { const [selectedModel, setSelectedModel] = useState( - STYLE_TRANSFER_CANDY_QUANTIZED + MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ quant: true }) ); const model = useStyleTransfer({ model: selectedModel }); diff --git a/apps/computer-vision/app/text_to_image/index.tsx b/apps/computer-vision/app/text_to_image/index.tsx index 6af71227e9..cfc63b8bca 100644 --- a/apps/computer-vision/app/text_to_image/index.tsx +++ b/apps/computer-vision/app/text_to_image/index.tsx @@ -14,9 +14,8 @@ import React, { useContext, useEffect, useState } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import Spinner from '../../components/Spinner'; import { + MODEL_REGISTRY, useTextToImage, - BK_SDM_TINY_VPRED_256, - BK_SDM_TINY_VPRED_512, TextToImageProps, } from 'react-native-executorch'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; @@ -30,8 +29,14 @@ import ErrorBanner from '../../components/ErrorBanner'; type TextToImageModelSources = TextToImageProps['model']; const MODELS: ModelOption[] = [ - { label: 'BK-SDM 256', value: BK_SDM_TINY_VPRED_256 }, - { label: 'BK-SDM 512', value: BK_SDM_TINY_VPRED_512 }, + { + label: 'BK-SDM 256', + value: MODEL_REGISTRY.IMAGE_GENERATION.BK_SDM_TINY_VPRED_256, + }, + { + label: 'BK-SDM 512', + value: MODEL_REGISTRY.IMAGE_GENERATION.BK_SDM_TINY_VPRED_512, + }, ]; export default function TextToImageScreen() { @@ -42,7 +47,7 @@ export default function TextToImageScreen() { const [input, setInput] = useState(''); const [selectedModel, setSelectedModel] = useState( - BK_SDM_TINY_VPRED_256 + MODEL_REGISTRY.IMAGE_GENERATION.BK_SDM_TINY_VPRED_256 ); const [generationTime, setGenerationTime] = useState(null); diff --git a/apps/computer-vision/components/vision_camera/tasks/ClassificationTask.tsx b/apps/computer-vision/components/vision_camera/tasks/ClassificationTask.tsx index ef0046a297..aed460327f 100644 --- a/apps/computer-vision/components/vision_camera/tasks/ClassificationTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/ClassificationTask.tsx @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { Frame, useFrameOutput } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; -import { EFFICIENTNET_V2_S, useClassification } from 'react-native-executorch'; +import { MODEL_REGISTRY, useClassification } from 'react-native-executorch'; import { FRAME_TARGET_RESOLUTION, TaskProps } from './types'; type Props = Omit< @@ -19,7 +19,9 @@ export default function ClassificationTask({ onFpsChange, onErrorChange, }: Props) { - const model = useClassification({ model: EFFICIENTNET_V2_S }); + const model = useClassification({ + model: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S, + }); const [classResult, setClassResult] = useState({ label: '', score: 0 }); const lastFrameTimeRef = useRef(Date.now()); diff --git a/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx b/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx index 52251f6e3e..930f69ce79 100644 --- a/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx @@ -3,11 +3,8 @@ import { StyleSheet, Text, View } from 'react-native'; import { Frame, useFrameOutput } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; import { + MODEL_REGISTRY, SegmentedInstance, - YOLO26N_SEG, - RF_DETR_NANO_SEG, - FASTSAM_S, - FASTSAM_X, useInstanceSegmentation, CocoLabel, CocoLabelYolo, @@ -42,19 +39,19 @@ export default function InstanceSegmentationTask({ onErrorChange, }: Props) { const yolo26n = useInstanceSegmentation({ - model: YOLO26N_SEG, + model: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26N_SEG, preventLoad: activeModel !== 'instanceSegmentationYolo26n', }); const rfdetr = useInstanceSegmentation({ - model: RF_DETR_NANO_SEG, + model: MODEL_REGISTRY.INSTANCE_SEGMENTATION.RF_DETR_NANO_SEG, preventLoad: activeModel !== 'instanceSegmentationRfdetr', }); const fastsamS = useInstanceSegmentation({ - model: FASTSAM_S, + model: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_S, preventLoad: activeModel !== 'instanceSegmentationFastsamS', }); const fastsamX = useInstanceSegmentation({ - model: FASTSAM_X, + model: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_X, preventLoad: activeModel !== 'instanceSegmentationFastsamX', }); diff --git a/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx b/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx index 992a8eaad0..3f00f40da9 100644 --- a/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx @@ -3,10 +3,8 @@ import { StyleSheet, View } from 'react-native'; import { Frame, useFrameOutput } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; import { + MODEL_REGISTRY, Detection, - RF_DETR_NANO, - SSDLITE_320_MOBILENET_V3_LARGE, - YOLO26N, useObjectDetection, CocoLabel, CocoLabelYolo, @@ -34,15 +32,15 @@ export default function ObjectDetectionTask({ onErrorChange, }: Props) { const ssdlite = useObjectDetection({ - model: SSDLITE_320_MOBILENET_V3_LARGE, + model: MODEL_REGISTRY.OBJECT_DETECTION.SSDLITE_320_MOBILENET_V3_LARGE, preventLoad: activeModel !== 'objectDetectionSsdlite', }); const rfdetr = useObjectDetection({ - model: RF_DETR_NANO, + model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO, preventLoad: activeModel !== 'objectDetectionRfdetr', }); const yolo26n = useObjectDetection({ - model: YOLO26N, + model: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26N, preventLoad: activeModel !== 'objectDetectionYolo26n', }); diff --git a/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx b/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx index b06f2ff9d1..c46c924a02 100644 --- a/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx @@ -3,13 +3,7 @@ import { StyleSheet, View } from 'react-native'; import { Frame, useFrameOutput } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; import { - DEEPLAB_V3_RESNET50_QUANTIZED, - DEEPLAB_V3_RESNET101_QUANTIZED, - DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED, - FCN_RESNET50_QUANTIZED, - FCN_RESNET101_QUANTIZED, - LRASPP_MOBILENET_V3_LARGE_QUANTIZED, - SELFIE_SEGMENTATION, + MODEL_REGISTRY, useSemanticSegmentation, } from 'react-native-executorch'; import { @@ -47,31 +41,39 @@ export default function SegmentationTask({ onErrorChange, }: Props) { const segDeeplabResnet50 = useSemanticSegmentation({ - model: DEEPLAB_V3_RESNET50_QUANTIZED, + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET50({ + quant: true, + }), preventLoad: activeModel !== 'segmentationDeeplabResnet50', }); const segDeeplabResnet101 = useSemanticSegmentation({ - model: DEEPLAB_V3_RESNET101_QUANTIZED, + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET101({ + quant: true, + }), preventLoad: activeModel !== 'segmentationDeeplabResnet101', }); const segDeeplabMobilenet = useSemanticSegmentation({ - model: DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED, + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE({ + quant: true, + }), preventLoad: activeModel !== 'segmentationDeeplabMobilenet', }); const segLraspp = useSemanticSegmentation({ - model: LRASPP_MOBILENET_V3_LARGE_QUANTIZED, + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.LRASPP_MOBILENET_V3_LARGE({ + quant: true, + }), preventLoad: activeModel !== 'segmentationLraspp', }); const segFcnResnet50 = useSemanticSegmentation({ - model: FCN_RESNET50_QUANTIZED, + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET50({ quant: true }), preventLoad: activeModel !== 'segmentationFcnResnet50', }); const segFcnResnet101 = useSemanticSegmentation({ - model: FCN_RESNET101_QUANTIZED, + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET101({ quant: true }), preventLoad: activeModel !== 'segmentationFcnResnet101', }); const segSelfie = useSemanticSegmentation({ - model: SELFIE_SEGMENTATION, + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.SELFIE_SEGMENTATION, preventLoad: activeModel !== 'segmentationSelfie', }); diff --git a/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx b/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx index 6361970bfc..dfd6b8d4e9 100644 --- a/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx @@ -2,11 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { StyleSheet, View } from 'react-native'; import { Frame, useFrameOutput } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; -import { - STYLE_TRANSFER_CANDY, - STYLE_TRANSFER_MOSAIC, - useStyleTransfer, -} from 'react-native-executorch'; +import { MODEL_REGISTRY, useStyleTransfer } from 'react-native-executorch'; import { AlphaType, Canvas, @@ -34,11 +30,11 @@ export default function StyleTransferTask({ onErrorChange, }: Props) { const candy = useStyleTransfer({ - model: STYLE_TRANSFER_CANDY, + model: MODEL_REGISTRY.STYLE_TRANSFER.CANDY, preventLoad: activeModel !== 'styleTransferCandy', }); const mosaic = useStyleTransfer({ - model: STYLE_TRANSFER_MOSAIC, + model: MODEL_REGISTRY.STYLE_TRANSFER.MOSAIC, preventLoad: activeModel !== 'styleTransferMosaic', }); diff --git a/apps/llm/app/llm/index.tsx b/apps/llm/app/llm/index.tsx index 901b74de43..a31d7a6ff9 100644 --- a/apps/llm/app/llm/index.tsx +++ b/apps/llm/app/llm/index.tsx @@ -11,7 +11,7 @@ import { View, } from 'react-native'; import SendIcon from '../../assets/icons/send_icon.svg'; -import { useLLM, LLAMA3_2_1B_SPINQUANT } from 'react-native-executorch'; +import { MODEL_REGISTRY, useLLM } from 'react-native-executorch'; import { ModelPicker } from '../../components/ModelPicker'; import { LLM_MODELS, LLMModelSources } from '../../components/llmModels'; import PauseIcon from '../../assets/icons/pause_icon.svg'; @@ -43,7 +43,7 @@ function LLMScreen() { const [isTextInputFocused, setIsTextInputFocused] = useState(false); const [userInput, setUserInput] = useState(''); const [selectedModel, setSelectedModel] = useState( - LLAMA3_2_1B_SPINQUANT + MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }) ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/llm_structured_output/index.tsx b/apps/llm/app/llm_structured_output/index.tsx index aea47b8136..b72defece4 100644 --- a/apps/llm/app/llm_structured_output/index.tsx +++ b/apps/llm/app/llm_structured_output/index.tsx @@ -24,10 +24,10 @@ import { useLLMStats } from '../../hooks/useLLMStats'; import { StatsBar } from '../../components/StatsBar'; import ErrorBanner from '../../components/ErrorBanner'; import { + MODEL_REGISTRY, useLLM, fixAndValidateStructuredOutput, getStructuredOutputPrompt, - QWEN3_1_7B_QUANTIZED, } from 'react-native-executorch'; import { ModelPicker } from '../../components/ModelPicker'; import { LLM_MODELS, LLMModelSources } from '../../components/llmModels'; @@ -83,8 +83,9 @@ export default function LLMScreenWrapper() { function LLMScreen() { const [isTextInputFocused, setIsTextInputFocused] = useState(false); const [userInput, setUserInput] = useState(''); - const [selectedModel, setSelectedModel] = - useState(QWEN3_1_7B_QUANTIZED); + const [selectedModel, setSelectedModel] = useState( + MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: true }) + ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/llm_tool_calling/index.tsx b/apps/llm/app/llm_tool_calling/index.tsx index 2ef688ed69..59388ce76e 100644 --- a/apps/llm/app/llm_tool_calling/index.tsx +++ b/apps/llm/app/llm_tool_calling/index.tsx @@ -18,9 +18,9 @@ import SendIcon from '../../assets/icons/send_icon.svg'; import Spinner from '../../components/Spinner'; import ErrorBanner from '../../components/ErrorBanner'; import { + MODEL_REGISTRY, useLLM, DEFAULT_SYSTEM_PROMPT, - HAMMER2_1_1_5B_QUANTIZED, } from 'react-native-executorch'; import { ModelPicker } from '../../components/ModelPicker'; import { LLM_MODELS, LLMModelSources } from '../../components/llmModels'; @@ -55,7 +55,7 @@ function LLMToolCallingScreen() { const [hasCalendarPermission, setHasCalendarPermission] = useState(true); const [hasBrightnessPermission, setHasBrightnessPermission] = useState(true); const [selectedModel, setSelectedModel] = useState( - HAMMER2_1_1_5B_QUANTIZED + MODEL_REGISTRY.LLM.HAMMER2_1_1_5B({ quant: true }) ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/multimodal_llm/index.tsx b/apps/llm/app/multimodal_llm/index.tsx index b7d6859ede..22dee14419 100644 --- a/apps/llm/app/multimodal_llm/index.tsx +++ b/apps/llm/app/multimodal_llm/index.tsx @@ -14,7 +14,7 @@ import { import { launchImageLibrary } from 'react-native-image-picker'; import { useIsFocused } from '@react-navigation/native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { useLLM, LFM2_5_VL_1_6B_QUANTIZED } from 'react-native-executorch'; +import { MODEL_REGISTRY, useLLM } from 'react-native-executorch'; import SendIcon from '../../assets/icons/send_icon.svg'; import PauseIcon from '../../assets/icons/pause_icon.svg'; import ColorPalette from '../../colors'; @@ -50,7 +50,7 @@ function MultimodalLLMScreen() { const [error, setError] = useState(null); const vlm = useLLM({ - model: LFM2_5_VL_1_6B_QUANTIZED, + model: MODEL_REGISTRY.VLM.LFM2_5_VL_1_6B, }); const tokenCount = vlm.isReady ? vlm.getGeneratedTokenCount() : 0; const { stats, onMessageSend } = useLLMStats( diff --git a/apps/llm/app/voice_chat/index.tsx b/apps/llm/app/voice_chat/index.tsx index 23ab70bff4..991031afa3 100644 --- a/apps/llm/app/voice_chat/index.tsx +++ b/apps/llm/app/voice_chat/index.tsx @@ -13,15 +13,9 @@ import SWMIcon from '../../assets/icons/swm_icon.svg'; import Spinner from '../../components/Spinner'; import ErrorBanner from '../../components/ErrorBanner'; import { + MODEL_REGISTRY, useSpeechToText, useLLM, - QWEN3_0_6B_QUANTIZED, - QWEN3_1_7B_QUANTIZED, - LLAMA3_2_1B_SPINQUANT, - WHISPER_TINY_EN, - WHISPER_TINY_EN_QUANTIZED, - WHISPER_BASE_EN, - WHISPER_SMALL_EN, LLMProps, SpeechToTextProps, } from 'react-native-executorch'; @@ -41,16 +35,34 @@ type LLMModelSources = LLMProps['model']; type STTModelSources = SpeechToTextProps['model']; const LLM_MODELS: ModelOption[] = [ - { label: 'Qwen3 0.6B', value: QWEN3_0_6B_QUANTIZED }, - { label: 'Qwen3 1.7B', value: QWEN3_1_7B_QUANTIZED }, - { label: 'Llama 1B', value: LLAMA3_2_1B_SPINQUANT }, + { + label: 'Qwen3 0.6B', + value: MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: true }), + }, + { + label: 'Qwen3 1.7B', + value: MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: true }), + }, + { label: 'Llama 1B', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }) }, ]; const STT_MODELS: ModelOption[] = [ - { label: 'Whisper Tiny', value: WHISPER_TINY_EN }, - { label: 'Whisper Tiny Q', value: WHISPER_TINY_EN_QUANTIZED }, - { label: 'Whisper Base', value: WHISPER_BASE_EN }, - { label: 'Whisper Small', value: WHISPER_SMALL_EN }, + { + label: 'Whisper Tiny', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, + }, + { + label: 'Whisper Tiny Q', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: true }), + }, + { + label: 'Whisper Base', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_BASE_EN, + }, + { + label: 'Whisper Small', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_SMALL_EN, + }, ]; export default function VoiceChatScreenWrapper() { @@ -63,10 +75,12 @@ function VoiceChatScreen() { const { bottom } = useSafeAreaInsets(); const [isRecording, setIsRecording] = useState(false); const [liveTranscription, setLiveTranscription] = useState(''); - const [selectedLLM, setSelectedLLM] = - useState(QWEN3_0_6B_QUANTIZED); - const [selectedSTT, setSelectedSTT] = - useState(WHISPER_TINY_EN); + const [selectedLLM, setSelectedLLM] = useState( + MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: true }) + ); + const [selectedSTT, setSelectedSTT] = useState( + MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN + ); const [error, setError] = useState(null); const [recorder] = useState(() => new AudioRecorder()); diff --git a/apps/llm/components/llmModels.ts b/apps/llm/components/llmModels.ts index 593db478b3..de42f72ed9 100644 --- a/apps/llm/components/llmModels.ts +++ b/apps/llm/components/llmModels.ts @@ -1,45 +1,8 @@ import { - LLAMA3_2_1B, + MODEL_REGISTRY, LLAMA3_2_1B_QLORA, - LLAMA3_2_1B_SPINQUANT, - LLAMA3_2_3B, LLAMA3_2_3B_QLORA, - LLAMA3_2_3B_SPINQUANT, - QWEN3_0_6B, - QWEN3_0_6B_QUANTIZED, - QWEN3_1_7B, - QWEN3_1_7B_QUANTIZED, - QWEN3_4B, - QWEN3_4B_QUANTIZED, - HAMMER2_1_0_5B, - HAMMER2_1_0_5B_QUANTIZED, - HAMMER2_1_1_5B, - HAMMER2_1_1_5B_QUANTIZED, - HAMMER2_1_3B, - HAMMER2_1_3B_QUANTIZED, - SMOLLM2_1_135M, - SMOLLM2_1_135M_QUANTIZED, - SMOLLM2_1_360M, - SMOLLM2_1_360M_QUANTIZED, - SMOLLM2_1_1_7B, - SMOLLM2_1_1_7B_QUANTIZED, - QWEN2_5_0_5B, - QWEN2_5_0_5B_QUANTIZED, - QWEN2_5_1_5B, - QWEN2_5_1_5B_QUANTIZED, - QWEN2_5_3B, - QWEN2_5_3B_QUANTIZED, - PHI_4_MINI_4B, - PHI_4_MINI_4B_QUANTIZED, - LFM2_5_350M, - LFM2_5_350M_QUANTIZED, - LFM2_5_1_2B_INSTRUCT, - LFM2_5_1_2B_INSTRUCT_QUANTIZED, LLMProps, - QWEN3_5_0_8B_QUANTIZED, - QWEN3_5_2B_QUANTIZED, - BIELIK_V3_0_1_5B_QUANTIZED, - BIELIK_V3_0_1_5B, } from 'react-native-executorch'; import { ModelOption } from './ModelPicker'; @@ -47,55 +10,109 @@ export type LLMModelSources = LLMProps['model']; export const LLM_MODELS: ModelOption[] = [ // Llama 3.2 - { label: 'Llama 3.2 1B', value: LLAMA3_2_1B }, + { label: 'Llama 3.2 1B', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B }, { label: 'Llama 3.2 1B QLoRA', value: LLAMA3_2_1B_QLORA }, - { label: 'Llama 3.2 1B SpinQuant', value: LLAMA3_2_1B_SPINQUANT }, - { label: 'Llama 3.2 3B', value: LLAMA3_2_3B }, + { + label: 'Llama 3.2 1B SpinQuant', + value: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }), + }, + { label: 'Llama 3.2 3B', value: MODEL_REGISTRY.LLM.LLAMA3_2_3B }, { label: 'Llama 3.2 3B QLoRA', value: LLAMA3_2_3B_QLORA }, - { label: 'Llama 3.2 3B SpinQuant', value: LLAMA3_2_3B_SPINQUANT }, + { + label: 'Llama 3.2 3B SpinQuant', + value: MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true }), + }, // Qwen3 - { label: 'Qwen3 0.6B', value: QWEN3_0_6B }, - { label: 'Qwen3 0.6B Quantized', value: QWEN3_0_6B_QUANTIZED }, - { label: 'Qwen3 1.7B', value: QWEN3_1_7B }, - { label: 'Qwen3 1.7B Quantized', value: QWEN3_1_7B_QUANTIZED }, - { label: 'Qwen3 4B', value: QWEN3_4B }, - { label: 'Qwen3 4B Quantized', value: QWEN3_4B_QUANTIZED }, + { label: 'Qwen3 0.6B', value: MODEL_REGISTRY.LLM.QWEN3_0_6B }, + { + label: 'Qwen3 0.6B Quantized', + value: MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: true }), + }, + { label: 'Qwen3 1.7B', value: MODEL_REGISTRY.LLM.QWEN3_1_7B }, + { + label: 'Qwen3 1.7B Quantized', + value: MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: true }), + }, + { label: 'Qwen3 4B', value: MODEL_REGISTRY.LLM.QWEN3_4B }, + { + label: 'Qwen3 4B Quantized', + value: MODEL_REGISTRY.LLM.QWEN3_4B({ quant: true }), + }, // Hammer 2.1 - { label: 'Hammer 2.1 0.5B', value: HAMMER2_1_0_5B }, - { label: 'Hammer 2.1 0.5B Quantized', value: HAMMER2_1_0_5B_QUANTIZED }, - { label: 'Hammer 2.1 1.5B', value: HAMMER2_1_1_5B }, - { label: 'Hammer 2.1 1.5B Quantized', value: HAMMER2_1_1_5B_QUANTIZED }, - { label: 'Hammer 2.1 3B', value: HAMMER2_1_3B }, - { label: 'Hammer 2.1 3B Quantized', value: HAMMER2_1_3B_QUANTIZED }, + { label: 'Hammer 2.1 0.5B', value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B }, + { + label: 'Hammer 2.1 0.5B Quantized', + value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B({ quant: true }), + }, + { label: 'Hammer 2.1 1.5B', value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B }, + { + label: 'Hammer 2.1 1.5B Quantized', + value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B({ quant: true }), + }, + { label: 'Hammer 2.1 3B', value: MODEL_REGISTRY.LLM.HAMMER2_1_3B }, + { + label: 'Hammer 2.1 3B Quantized', + value: MODEL_REGISTRY.LLM.HAMMER2_1_3B({ quant: true }), + }, // SmolLM2 - { label: 'SmolLM2 135M', value: SMOLLM2_1_135M }, - { label: 'SmolLM2 135M Quantized', value: SMOLLM2_1_135M_QUANTIZED }, - { label: 'SmolLM2 360M', value: SMOLLM2_1_360M }, - { label: 'SmolLM2 360M Quantized', value: SMOLLM2_1_360M_QUANTIZED }, - { label: 'SmolLM2 1.7B', value: SMOLLM2_1_1_7B }, - { label: 'SmolLM2 1.7B Quantized', value: SMOLLM2_1_1_7B_QUANTIZED }, + { label: 'SmolLM2 135M', value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M }, + { + label: 'SmolLM2 135M Quantized', + value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M({ quant: true }), + }, + { label: 'SmolLM2 360M', value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M }, + { + label: 'SmolLM2 360M Quantized', + value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M({ quant: true }), + }, + { label: 'SmolLM2 1.7B', value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B }, + { + label: 'SmolLM2 1.7B Quantized', + value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B({ quant: true }), + }, // Qwen2.5 - { label: 'Qwen2.5 0.5B', value: QWEN2_5_0_5B }, - { label: 'Qwen2.5 0.5B Quantized', value: QWEN2_5_0_5B_QUANTIZED }, - { label: 'Qwen2.5 1.5B', value: QWEN2_5_1_5B }, - { label: 'Qwen2.5 1.5B Quantized', value: QWEN2_5_1_5B_QUANTIZED }, - { label: 'Qwen2.5 3B', value: QWEN2_5_3B }, - { label: 'Qwen2.5 3B Quantized', value: QWEN2_5_3B_QUANTIZED }, + { label: 'Qwen2.5 0.5B', value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B }, + { + label: 'Qwen2.5 0.5B Quantized', + value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B({ quant: true }), + }, + { label: 'Qwen2.5 1.5B', value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B }, + { + label: 'Qwen2.5 1.5B Quantized', + value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B({ quant: true }), + }, + { label: 'Qwen2.5 3B', value: MODEL_REGISTRY.LLM.QWEN2_5_3B }, + { + label: 'Qwen2.5 3B Quantized', + value: MODEL_REGISTRY.LLM.QWEN2_5_3B({ quant: true }), + }, // Qwen3.5 - { label: 'Qwen3.5 0.8B Quantized', value: QWEN3_5_0_8B_QUANTIZED }, - { label: 'Qwen3.5 2B Quantized', value: QWEN3_5_2B_QUANTIZED }, + { label: 'Qwen3.5 0.8B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_5_0_8B }, + { label: 'Qwen3.5 2B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_5_2B }, // Phi-4 - { label: 'Phi-4 Mini 4B', value: PHI_4_MINI_4B }, - { label: 'Phi-4 Mini 4B Quantized', value: PHI_4_MINI_4B_QUANTIZED }, + { label: 'Phi-4 Mini 4B', value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B }, + { + label: 'Phi-4 Mini 4B Quantized', + value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B({ quant: true }), + }, // LFM2.5 - { label: 'LFM2.5 350M', value: LFM2_5_350M }, - { label: 'LFM2.5 350M Quantized', value: LFM2_5_350M_QUANTIZED }, - { label: 'LFM2.5 1.2B Instruct', value: LFM2_5_1_2B_INSTRUCT }, + { label: 'LFM2.5 350M', value: MODEL_REGISTRY.LLM.LFM2_5_350M }, + { + label: 'LFM2.5 350M Quantized', + value: MODEL_REGISTRY.LLM.LFM2_5_350M({ quant: true }), + }, + { + label: 'LFM2.5 1.2B Instruct', + value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT, + }, { label: 'LFM2.5 1.2B Instruct Quantized', - value: LFM2_5_1_2B_INSTRUCT_QUANTIZED, + value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT({ quant: true }), }, // Bielik v3.0 - { label: 'Bielik v3.0 1.5B', value: BIELIK_V3_0_1_5B }, - { label: 'Bielik v3.0 1.5B Quantized', value: BIELIK_V3_0_1_5B_QUANTIZED }, + { label: 'Bielik v3.0 1.5B', value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B }, + { + label: 'Bielik v3.0 1.5B Quantized', + value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B({ quant: true }), + }, ]; diff --git a/apps/speech/screens/SpeechToTextScreen.tsx b/apps/speech/screens/SpeechToTextScreen.tsx index dfd39c15b4..a1d5997d54 100644 --- a/apps/speech/screens/SpeechToTextScreen.tsx +++ b/apps/speech/screens/SpeechToTextScreen.tsx @@ -12,11 +12,8 @@ import { } from 'react-native'; import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'; import { + MODEL_REGISTRY, useSpeechToText, - WHISPER_TINY_EN, - WHISPER_TINY_EN_QUANTIZED, - WHISPER_BASE_EN, - WHISPER_SMALL_EN, TranscriptionResult, SpeechToTextProps, } from 'react-native-executorch'; @@ -25,10 +22,22 @@ import { ModelPicker, ModelOption } from '../components/ModelPicker'; type STTModelSources = SpeechToTextProps['model']; const MODELS: ModelOption[] = [ - { label: 'Whisper Tiny', value: WHISPER_TINY_EN }, - { label: 'Whisper Tiny Q', value: WHISPER_TINY_EN_QUANTIZED }, - { label: 'Whisper Base', value: WHISPER_BASE_EN }, - { label: 'Whisper Small', value: WHISPER_SMALL_EN }, + { + label: 'Whisper Tiny', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, + }, + { + label: 'Whisper Tiny Q', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: true }), + }, + { + label: 'Whisper Base', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_BASE_EN, + }, + { + label: 'Whisper Small', + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_SMALL_EN, + }, ]; import FontAwesome from '@expo/vector-icons/FontAwesome'; import { @@ -46,8 +55,9 @@ import ErrorBanner from '../components/ErrorBanner'; const isSimulator = DeviceInfo.isEmulatorSync(); export const SpeechToTextScreen = ({ onBack }: { onBack: () => void }) => { - const [selectedModel, setSelectedModel] = - useState(WHISPER_TINY_EN); + const [selectedModel, setSelectedModel] = useState( + MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN + ); const model = useSpeechToText({ model: selectedModel, diff --git a/apps/text-embeddings/app/clip-embeddings/index.tsx b/apps/text-embeddings/app/clip-embeddings/index.tsx index c88220eb4f..77f2516c02 100644 --- a/apps/text-embeddings/app/clip-embeddings/index.tsx +++ b/apps/text-embeddings/app/clip-embeddings/index.tsx @@ -13,19 +13,25 @@ import { } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { + MODEL_REGISTRY, useTextEmbeddings, useImageEmbeddings, - CLIP_VIT_BASE_PATCH32_TEXT, - CLIP_VIT_BASE_PATCH32_IMAGE, - CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED, ImageEmbeddingsProps, } from 'react-native-executorch'; type ImageEmbeddingModel = ImageEmbeddingsProps['model']; const IMAGE_MODELS: { label: string; value: ImageEmbeddingModel }[] = [ - { label: 'ViT-B/32 Quantized', value: CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED }, - { label: 'ViT-B/32 FP32', value: CLIP_VIT_BASE_PATCH32_IMAGE }, + { + label: 'ViT-B/32 Quantized', + value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ + quant: true, + }), + }, + { + label: 'ViT-B/32 FP32', + value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE, + }, ]; import { launchImageLibrary } from 'react-native-image-picker'; import { useIsFocused } from '@react-navigation/native'; @@ -48,9 +54,15 @@ export default function ClipEmbeddingsScreenWrapper() { function ClipEmbeddingsScreen() { const [selectedImageModel, setSelectedImageModel] = - useState(CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED); + useState( + MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ + quant: true, + }) + ); - const textModel = useTextEmbeddings({ model: CLIP_VIT_BASE_PATCH32_TEXT }); + const textModel = useTextEmbeddings({ + model: MODEL_REGISTRY.TEXT_EMBEDDING.CLIP_VIT_BASE_PATCH32_TEXT, + }); const imageModel = useImageEmbeddings({ model: selectedImageModel }); const [imageUri, setImageUri] = useState(null); diff --git a/apps/text-embeddings/app/text-embeddings/index.tsx b/apps/text-embeddings/app/text-embeddings/index.tsx index 492cdf48b1..90f059a51a 100644 --- a/apps/text-embeddings/app/text-embeddings/index.tsx +++ b/apps/text-embeddings/app/text-embeddings/index.tsx @@ -13,35 +13,40 @@ import { import { Ionicons } from '@expo/vector-icons'; import { ModelPicker } from '../../components/ModelPicker'; import { + MODEL_REGISTRY, useTextEmbeddings, - ALL_MINILM_L6_V2, - ALL_MPNET_BASE_V2, - MULTI_QA_MINILM_L6_COS_V1, - MULTI_QA_MPNET_BASE_DOT_V1, - DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W, - DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML, - PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED, TextEmbeddingsProps, } from 'react-native-executorch'; type TextEmbeddingModel = TextEmbeddingsProps['model']; const MODELS: { label: string; value: TextEmbeddingModel }[] = [ - { label: 'MiniLM L6', value: ALL_MINILM_L6_V2 }, - { label: 'MPNet Base', value: ALL_MPNET_BASE_V2 }, - { label: 'MultiQA MiniLM', value: MULTI_QA_MINILM_L6_COS_V1 }, - { label: 'MultiQA MPNet', value: MULTI_QA_MPNET_BASE_DOT_V1 }, + { label: 'MiniLM L6', value: MODEL_REGISTRY.TEXT_EMBEDDING.ALL_MINILM_L6_V2 }, + { + label: 'MPNet Base', + value: MODEL_REGISTRY.TEXT_EMBEDDING.ALL_MPNET_BASE_V2, + }, + { + label: 'MultiQA MiniLM', + value: MODEL_REGISTRY.TEXT_EMBEDDING.MULTI_QA_MINILM_L6_COS_V1, + }, + { + label: 'MultiQA MPNet', + value: MODEL_REGISTRY.TEXT_EMBEDDING.MULTI_QA_MPNET_BASE_DOT_V1, + }, { label: 'Multilingual DistilUSE (8da4w)', - value: DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W, + value: + MODEL_REGISTRY.TEXT_EMBEDDING.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W, }, { label: 'Multilingual DistilUSE (CoreML)', - value: DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML, + value: + MODEL_REGISTRY.TEXT_EMBEDDING.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML, }, { label: 'Multilingual Paraphrase (8da4w)', - value: PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED, + value: MODEL_REGISTRY.TEXT_EMBEDDING.PARAPHRASE_MULTILINGUAL_MINILM_L12_V2, }, ]; import { useIsFocused } from '@react-navigation/native'; @@ -55,8 +60,9 @@ export default function TextEmbeddingsScreenWrapper() { } function TextEmbeddingsScreen() { - const [selectedModel, setSelectedModel] = - useState(ALL_MINILM_L6_V2); + const [selectedModel, setSelectedModel] = useState( + MODEL_REGISTRY.TEXT_EMBEDDING.ALL_MINILM_L6_V2 + ); const model = useTextEmbeddings({ model: selectedModel }); const [error, setError] = useState(null); From 3cfdd22fc562a083ff37241734e4aa33aea78caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Wed, 13 May 2026 19:26:20 +0200 Subject: [PATCH 05/16] fix(apps): compare picker entries by modelName to handle accessor functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useState auto-invokes function-typed initial values as lazy initializers, so passing a MODEL_REGISTRY accessor unwraps it into a plain config — breaking reference equality against the accessor stored in MODELS. Compare by modelName (falling back to === for picker users without one, e.g. VoiceConfig). --- apps/computer-vision/components/ModelPicker.tsx | 15 +++++++++++++-- apps/llm/components/ModelPicker.tsx | 15 +++++++++++++-- apps/speech/components/ModelPicker.tsx | 15 +++++++++++++-- apps/text-embeddings/components/ModelPicker.tsx | 15 +++++++++++++-- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/apps/computer-vision/components/ModelPicker.tsx b/apps/computer-vision/components/ModelPicker.tsx index 94a848596e..483532f29a 100644 --- a/apps/computer-vision/components/ModelPicker.tsx +++ b/apps/computer-vision/components/ModelPicker.tsx @@ -24,6 +24,17 @@ type Props = { const DROPDOWN_MAX_HEIGHT = 200; +// MODEL_REGISTRY accessors are functions, so passing them to useState makes +// React auto-invoke them as lazy initializers — state becomes the underlying +// config object, breaking reference equality against the accessor in MODELS. +// Match by modelName when both sides expose one, otherwise fall back to ===. +function sameValue(a: T, b: T): boolean { + const am = (a as { modelName?: unknown })?.modelName; + const bm = (b as { modelName?: unknown })?.modelName; + if (typeof am === 'string' && typeof bm === 'string') return am === bm; + return a === b; +} + export function ModelPicker({ models, selectedModel, @@ -36,7 +47,7 @@ export function ModelPicker({ const [expandUp, setExpandUp] = useState(false); const [dropdownTop, setDropdownTop] = useState(0); const triggerRef = useRef>(null); - const selected = models.find((m) => m.value === selectedModel); + const selected = models.find((m) => sameValue(m.value, selectedModel)); useEffect(() => { if (disabled) setOpen(false); @@ -112,7 +123,7 @@ export function ModelPicker({ showsVerticalScrollIndicator={true} > {models.map((item) => { - const isSelected = item.value === selectedModel; + const isSelected = sameValue(item.value, selectedModel); return ( = { const DROPDOWN_MAX_HEIGHT = 200; +// MODEL_REGISTRY accessors are functions, so passing them to useState makes +// React auto-invoke them as lazy initializers — state becomes the underlying +// config object, breaking reference equality against the accessor in MODELS. +// Match by modelName when both sides expose one, otherwise fall back to ===. +function sameValue(a: T, b: T): boolean { + const am = (a as { modelName?: unknown })?.modelName; + const bm = (b as { modelName?: unknown })?.modelName; + if (typeof am === 'string' && typeof bm === 'string') return am === bm; + return a === b; +} + export function ModelPicker({ models, selectedModel, @@ -36,7 +47,7 @@ export function ModelPicker({ const [expandUp, setExpandUp] = useState(false); const [dropdownTop, setDropdownTop] = useState(0); const triggerRef = useRef>(null); - const selected = models.find((m) => m.value === selectedModel); + const selected = models.find((m) => sameValue(m.value, selectedModel)); useEffect(() => { if (disabled) setOpen(false); @@ -112,7 +123,7 @@ export function ModelPicker({ showsVerticalScrollIndicator={true} > {models.map((item) => { - const isSelected = item.value === selectedModel; + const isSelected = sameValue(item.value, selectedModel); return ( = { const DROPDOWN_MAX_HEIGHT = 200; +// MODEL_REGISTRY accessors are functions, so passing them to useState makes +// React auto-invoke them as lazy initializers — state becomes the underlying +// config object, breaking reference equality against the accessor in MODELS. +// Match by modelName when both sides expose one, otherwise fall back to ===. +function sameValue(a: T, b: T): boolean { + const am = (a as { modelName?: unknown })?.modelName; + const bm = (b as { modelName?: unknown })?.modelName; + if (typeof am === 'string' && typeof bm === 'string') return am === bm; + return a === b; +} + export function ModelPicker({ models, selectedModel, @@ -34,7 +45,7 @@ export function ModelPicker({ const [triggerHeight, setTriggerHeight] = useState(0); const [expandUp, setExpandUp] = useState(false); const triggerRef = useRef>(null); - const selected = models.find((m) => m.value === selectedModel); + const selected = models.find((m) => sameValue(m.value, selectedModel)); useEffect(() => { if (disabled) setOpen(false); @@ -87,7 +98,7 @@ export function ModelPicker({ keyboardShouldPersistTaps="handled" > {models.map((item) => { - const isSelected = item.value === selectedModel; + const isSelected = sameValue(item.value, selectedModel); return ( = { const DROPDOWN_MAX_HEIGHT = 200; +// MODEL_REGISTRY accessors are functions, so passing them to useState makes +// React auto-invoke them as lazy initializers — state becomes the underlying +// config object, breaking reference equality against the accessor in MODELS. +// Match by modelName when both sides expose one, otherwise fall back to ===. +function sameValue(a: T, b: T): boolean { + const am = (a as { modelName?: unknown })?.modelName; + const bm = (b as { modelName?: unknown })?.modelName; + if (typeof am === 'string' && typeof bm === 'string') return am === bm; + return a === b; +} + export function ModelPicker({ models, selectedModel, @@ -36,7 +47,7 @@ export function ModelPicker({ const [expandUp, setExpandUp] = useState(false); const [dropdownTop, setDropdownTop] = useState(0); const triggerRef = useRef>(null); - const selected = models.find((m) => m.value === selectedModel); + const selected = models.find((m) => sameValue(m.value, selectedModel)); useEffect(() => { if (disabled) setOpen(false); @@ -112,7 +123,7 @@ export function ModelPicker({ showsVerticalScrollIndicator={true} > {models.map((item) => { - const isSelected = item.value === selectedModel; + const isSelected = sameValue(item.value, selectedModel); return ( Date: Wed, 13 May 2026 19:46:31 +0200 Subject: [PATCH 06/16] feat(constants): wire up backend selection in MODEL_REGISTRY accessors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each accessor's `backend` parameter is now typed to exactly the backends the model ships with — passing an unsupported one is a compile-time error. `Platform.OS` still picks the default when `backend` is omitted. The per- backend (quant × backend) variant matrix lives in modelRegistry.ts so modelUrls.ts stays flat-per-model. Unifies DISTILUSE_BASE_MULTILINGUAL_CASED_V2 to one accessor with xnnpack + coreml; the _8DA4W and _COREML named constants stay as deprecated aliases. --- docs/docs/05-utilities/model-registry.md | 20 +- .../src/constants/modelRegistry.ts | 365 ++++++++++++++++-- .../src/constants/modelUrls.ts | 3 + 3 files changed, 346 insertions(+), 42 deletions(-) diff --git a/docs/docs/05-utilities/model-registry.md b/docs/docs/05-utilities/model-registry.md index 2d29966ade..0f870a7c52 100644 --- a/docs/docs/05-utilities/model-registry.md +++ b/docs/docs/05-utilities/model-registry.md @@ -36,14 +36,14 @@ const llmQuant = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })); ## Options ```typescript -type ModelOpts = { +type ModelOpts = { quant?: boolean; // Pick the quantized variant when true. Ignored when no quantized variant exists. - backend?: 'xnnpack' | 'coreml' | 'vulkan' | 'qnn'; // Reserved; today the platform default applies. + backend?: B; // Explicit backend; the set of allowed values is per-model. }; ``` - `quant: true` resolves to the quantized variant for models that publish one (e.g. `LLAMA3_2_3B` → SpinQuant, `EFFICIENTNET_V2_S` → int8). For models with a single variant, `quant` is accepted but has no effect. -- `backend` is accepted in the signature for forward-compatibility. Today every accessor returns a config whose backend is selected at module-load time by `Platform.OS`. Explicit per-backend selection is planned for a future release. +- `backend` selects an explicit backend. The accessor's call signature is typed to exactly the backends the model ships with, so requesting one the model doesn't publish is a compile-time error (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ backend: 'coreml' })` does not type-check — Llama 3.2 is xnnpack-only). When `backend` is omitted, the platform-default applies (typically CoreML on iOS and XNNPACK on Android for multi-backend models). ## Usage patterns @@ -70,6 +70,20 @@ const classifier = useClassification( ); ``` +### Explicit backend + +```typescript +// Force XNNPACK on iOS (overrides the CoreML default). +const detector = useObjectDetection({ + model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO({ backend: 'xnnpack' }), +}); + +// Combine `quant` and `backend`. +const styled = useStyleTransfer( + MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ backend: 'coreml', quant: true }) +); +``` + ### Inspecting a model's config Accessors transparently expose the default config's fields, so you can read them without calling: diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts index d6836919c2..45dd344cce 100644 --- a/packages/react-native-executorch/src/constants/modelRegistry.ts +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -1,69 +1,342 @@ +import { Platform } from 'react-native'; import * as M from './modelUrls'; +import { URL_PREFIX, VERSION_TAG } from './versions'; /** - * Backend options accepted by `MODEL_REGISTRY` accessors. The library currently - * picks a backend at module-load time based on `Platform.OS`; explicit - * `backend` selection is accepted in the signature for forward-compatibility - * but is not yet routed through to per-backend variants. + * Backend options accepted by `MODEL_REGISTRY` accessors. * + * The set of backends a particular model can be loaded with is encoded in + * its accessor's call signature — e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B` + * only accepts `'xnnpack'`, while `MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO` + * accepts `'xnnpack' | 'coreml'`. Passing a backend a model doesn't ship is + * a compile-time error. * @category Utils */ export type Backend = 'xnnpack' | 'coreml' | 'vulkan' | 'qnn'; /** * Options for a `MODEL_REGISTRY` accessor call. - * + * @typeParam B - Subset of {@link Backend} that the accessor actually supports. * @category Utils */ -export type ModelOpts = { - /** Pick the quantized variant when `true`. Ignored for models with no quantized counterpart. */ +export type ModelOpts = { + /** Pick the quantized variant when `true`. Ignored when a quantized variant is not published. */ quant?: boolean; - /** Reserved for explicit per-backend selection. Today the platform-default applies. */ - backend?: Backend; + /** Explicit backend; defaults to the platform-preferred backend for the model. */ + backend?: B; }; /** - * An accessor that behaves as the default model config when read as a value + * An accessor that behaves as the platform-default config when read as a value * (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelName`) and as a function when * called (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })`). */ -type Accessor = T & ((opts?: ModelOpts) => T); +type Accessor< + C extends { modelName: string }, + B extends Backend = Backend, +> = C & ((opts?: ModelOpts) => C); + +type BackendCell = { + default?: { modelName: string }; + quant?: { modelName: string }; +}; +type AnyVariantMap = Partial>; +type PlatformDefaults = { + ios?: B; + android?: B; + /** Fallback when no platform-specific default is set. */ + default?: B; +}; + +type CellConfig = T extends { default?: infer D; quant?: infer Q } + ? NonNullable | NonNullable + : never; +type ConfigOf = Extract< + { [K in keyof V]: CellConfig }[keyof V], + { modelName: string } +>; +type BackendsOf = Extract; + +const BACKEND_ORDER: Backend[] = ['xnnpack', 'coreml', 'vulkan', 'qnn']; + +function firstBackend(variants: AnyVariantMap): Backend { + for (const b of BACKEND_ORDER) { + if (variants[b]) return b; + } + throw new Error('Model variant map is empty.'); +} + +function resolveBackend( + variants: AnyVariantMap, + platformDefaults: PlatformDefaults | undefined, + requested: Backend | undefined +): Backend { + if (requested) return requested; + if (platformDefaults) { + if (Platform.OS === 'ios' && platformDefaults.ios) + return platformDefaults.ios; + if (Platform.OS === 'android' && platformDefaults.android) { + return platformDefaults.android; + } + if (platformDefaults.default) return platformDefaults.default; + } + return firstBackend(variants); +} + +function resolveCell(cell: BackendCell, quant: boolean): { modelName: string } { + // Fall back to the other slot when the requested precision is missing, + // so single-precision backends still work either way. + const primary = quant ? cell.quant : cell.default; + const fallback = quant ? cell.default : cell.quant; + const result = primary ?? fallback; + if (!result) { + throw new Error('Model variant cell has no config.'); + } + return result; +} + +function resolveVariant( + variants: AnyVariantMap, + platformDefaults: PlatformDefaults | undefined, + opts: ModelOpts +): { modelName: string } { + const backend = resolveBackend(variants, platformDefaults, opts.backend); + const cell = variants[backend]; + if (!cell) { + throw new Error(`Backend '${backend}' is not available for this model.`); + } + return resolveCell(cell, opts.quant === true); +} -function accessor( - defaultConfig: T, - resolve: (opts: ModelOpts) => T -): Accessor { - const fn = ((opts: ModelOpts = {}) => resolve(opts)) as Accessor; +// Build an Accessor from a per-backend variant map and an optional +// platform-default policy. The resulting accessor's `backend` parameter is +// typed to exactly the keys present in `variants`. +function variant( + variants: V, + platformDefaults?: PlatformDefaults> +): Accessor, BackendsOf> { + type C = ConfigOf; + type B = BackendsOf; + const defaultConfig = resolveVariant(variants, platformDefaults, {}) as C; + const fn = ((opts: ModelOpts = {}) => + resolveVariant(variants, platformDefaults, opts) as C) as Accessor; Object.assign(fn, defaultConfig); return fn; } -const base = (c: T) => accessor(c, () => c); +// Single-config accessor (xnnpack-only, no quantized variant). +function base(c: C) { + return variant({ xnnpack: { default: c } }); +} +// xnnpack-only accessor with a `default` / `quant` pair. function pair( defaultC: D, quantC: Q -): Accessor { - return accessor(defaultC, ({ quant = false } = {}) => - quant ? quantC : defaultC - ); +) { + return variant({ xnnpack: { default: defaultC, quant: quantC } }); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Per-backend variant maps for the models that ship more than one backend. +// +// Kept inline (rather than as new top-level constants in `modelUrls.ts`) so +// the (quant × backend) matrix lives next to the registry that consumes it. +// The Platform.OS-collapsed exports in `modelUrls.ts` remain the back-compat +// top-level imports. +// ───────────────────────────────────────────────────────────────────────────── + +const EFFICIENTNET_V2_S_VARIANTS = { + xnnpack: { + default: { + modelName: 'efficientnet-v2-s' as const, + modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_fp32.pte`, + }, + quant: { + modelName: 'efficientnet-v2-s-quantized' as const, + modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_int8.pte`, + }, + }, + coreml: { + default: { + modelName: 'efficientnet-v2-s' as const, + modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp32.pte`, + }, + quant: { + modelName: 'efficientnet-v2-s-quantized' as const, + modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp16.pte`, + }, + }, +}; + +const SSDLITE_320_MOBILENET_V3_LARGE_VARIANTS = { + xnnpack: { + default: { + modelName: 'ssdlite-320-mobilenet-v3-large' as const, + modelSource: `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/xnnpack/ssdlite320_mobilenet_v3_large_xnnpack_fp32.pte`, + }, + }, + coreml: { + default: { + modelName: 'ssdlite-320-mobilenet-v3-large' as const, + modelSource: `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/coreml/ssdlite320_mobilenet_v3_large_coreml_fp16.pte`, + }, + }, +}; + +const RF_DETR_NANO_VARIANTS = { + xnnpack: { + default: { + modelName: 'rf-detr-nano' as const, + modelSource: `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`, + }, + }, + coreml: { + default: { + modelName: 'rf-detr-nano' as const, + modelSource: `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`, + }, + }, +}; + +const RF_DETR_NANO_SEG_VARIANTS = { + xnnpack: { + default: { + modelName: 'rfdetr-nano-seg' as const, + modelSource: `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`, + }, + }, + coreml: { + default: { + modelName: 'rfdetr-nano-seg' as const, + modelSource: `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`, + }, + }, +}; + +const FASTSAM_S_VARIANTS = { + xnnpack: { + default: { + modelName: 'fastsam-s' as const, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`, + }, + }, + coreml: { + default: { + modelName: 'fastsam-s' as const, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte`, + }, + }, +}; + +const FASTSAM_X_VARIANTS = { + xnnpack: { + default: { + modelName: 'fastsam-x' as const, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`, + }, + }, + coreml: { + default: { + modelName: 'fastsam-x' as const, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte`, + }, + }, +}; + +function styleTransferVariants< + const Display extends string, + const Slug extends string, +>(display: Display, slug: Slug) { + return { + xnnpack: { + default: { + modelName: `style-transfer-${display}`, + modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/xnnpack/style_transfer_${slug}_xnnpack_fp32.pte`, + } as { + modelName: `style-transfer-${Display}`; + modelSource: string; + }, + quant: { + modelName: `style-transfer-${display}-quantized`, + modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/xnnpack/style_transfer_${slug}_xnnpack_int8.pte`, + } as { + modelName: `style-transfer-${Display}-quantized`; + modelSource: string; + }, + }, + coreml: { + default: { + modelName: `style-transfer-${display}`, + modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/coreml/style_transfer_${slug}_coreml_fp32.pte`, + } as { + modelName: `style-transfer-${Display}`; + modelSource: string; + }, + quant: { + modelName: `style-transfer-${display}-quantized`, + modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/coreml/style_transfer_${slug}_coreml_fp16.pte`, + } as { + modelName: `style-transfer-${Display}-quantized`; + modelSource: string; + }, + }, + }; } +const STYLE_TRANSFER_CANDY_VARIANTS = styleTransferVariants('candy', 'candy'); +const STYLE_TRANSFER_MOSAIC_VARIANTS = styleTransferVariants( + 'mosaic', + 'mosaic' +); +const STYLE_TRANSFER_RAIN_PRINCESS_VARIANTS = styleTransferVariants( + 'rain-princess', + 'rain_princess' +); +const STYLE_TRANSFER_UDNIE_VARIANTS = styleTransferVariants('udnie', 'udnie'); + +const DISTILUSE_TOKENIZER = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/tokenizer.json`; + +const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_VARIANTS = { + xnnpack: { + default: { + modelName: 'distiluse-base-multilingual-cased-v2-8da4w' as const, + modelSource: `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/xnnpack/distiluse_base_multilingual_cased_v2_xnnpack_8da4w.pte`, + tokenizerSource: DISTILUSE_TOKENIZER, + }, + }, + coreml: { + default: { + modelName: 'distiluse-base-multilingual-cased-v2-coreml' as const, + modelSource: `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/coreml/distiluse_base_multilingual_cased_v2_coreml_fp32.pte`, + tokenizerSource: DISTILUSE_TOKENIZER, + }, + }, +}; + +const COREML_ON_IOS = { ios: 'coreml', default: 'xnnpack' } as const; + /** * Typed model registry grouped by capability. Each entry exposes the model's - * default config and accepts `{ quant, backend }` for per-variant selection. - * + * platform-default config and accepts `{ quant, backend }` for per-variant + * selection. The `backend` parameter is typed to exactly the backends a given + * model ships with — asking for a backend a model doesn't publish is a + * compile-time error. * @example * ```ts * import { MODEL_REGISTRY } from 'react-native-executorch'; * - * // Default (non-quantized, platform-default backend) - * useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B); + * // Platform default (coreml on iOS, xnnpack on Android for multi-backend models). + * useObjectDetection({ model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO }); + * + * // Explicit backend. + * useObjectDetection({ + * model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO({ backend: 'xnnpack' }), + * }); * - * // Quantized variant + * // Quantized variant. * useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })); * ``` - * * @category Utils */ export const MODEL_REGISTRY = { @@ -97,20 +370,23 @@ export const MODEL_REGISTRY = { LFM2_5_VL_450M: base(M.LFM2_5_VL_450M_QUANTIZED), }, CLASSIFICATION: { - EFFICIENTNET_V2_S: pair(M.EFFICIENTNET_V2_S, M.EFFICIENTNET_V2_S_QUANTIZED), + EFFICIENTNET_V2_S: variant(EFFICIENTNET_V2_S_VARIANTS, COREML_ON_IOS), PRIVACY_FILTER_OPENAI: base(M.PRIVACY_FILTER_OPENAI), PRIVACY_FILTER_NEMOTRON: base(M.PRIVACY_FILTER_NEMOTRON), }, OBJECT_DETECTION: { - SSDLITE_320_MOBILENET_V3_LARGE: base(M.SSDLITE_320_MOBILENET_V3_LARGE), - RF_DETR_NANO: base(M.RF_DETR_NANO), + SSDLITE_320_MOBILENET_V3_LARGE: variant( + SSDLITE_320_MOBILENET_V3_LARGE_VARIANTS, + COREML_ON_IOS + ), + RF_DETR_NANO: variant(RF_DETR_NANO_VARIANTS, COREML_ON_IOS), YOLO26N: base(M.YOLO26N), YOLO26S: base(M.YOLO26S), YOLO26M: base(M.YOLO26M), YOLO26L: base(M.YOLO26L), YOLO26X: base(M.YOLO26X), - FASTSAM_S: base(M.FASTSAM_S), - FASTSAM_X: base(M.FASTSAM_X), + FASTSAM_S: variant(FASTSAM_S_VARIANTS, COREML_ON_IOS), + FASTSAM_X: variant(FASTSAM_X_VARIANTS, COREML_ON_IOS), }, SEMANTIC_SEGMENTATION: { DEEPLAB_V3_RESNET50: pair( @@ -139,16 +415,16 @@ export const MODEL_REGISTRY = { YOLO26M_SEG: base(M.YOLO26M_SEG), YOLO26L_SEG: base(M.YOLO26L_SEG), YOLO26X_SEG: base(M.YOLO26X_SEG), - RF_DETR_NANO_SEG: base(M.RF_DETR_NANO_SEG), + RF_DETR_NANO_SEG: variant(RF_DETR_NANO_SEG_VARIANTS, COREML_ON_IOS), }, STYLE_TRANSFER: { - CANDY: pair(M.STYLE_TRANSFER_CANDY, M.STYLE_TRANSFER_CANDY_QUANTIZED), - MOSAIC: pair(M.STYLE_TRANSFER_MOSAIC, M.STYLE_TRANSFER_MOSAIC_QUANTIZED), - RAIN_PRINCESS: pair( - M.STYLE_TRANSFER_RAIN_PRINCESS, - M.STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED + CANDY: variant(STYLE_TRANSFER_CANDY_VARIANTS, COREML_ON_IOS), + MOSAIC: variant(STYLE_TRANSFER_MOSAIC_VARIANTS, COREML_ON_IOS), + RAIN_PRINCESS: variant( + STYLE_TRANSFER_RAIN_PRINCESS_VARIANTS, + COREML_ON_IOS ), - UDNIE: pair(M.STYLE_TRANSFER_UDNIE, M.STYLE_TRANSFER_UDNIE_QUANTIZED), + UDNIE: variant(STYLE_TRANSFER_UDNIE_VARIANTS, COREML_ON_IOS), }, SPEECH_TO_TEXT: { WHISPER_TINY_EN: pair(M.WHISPER_TINY_EN, M.WHISPER_TINY_EN_QUANTIZED), @@ -163,9 +439,20 @@ export const MODEL_REGISTRY = { ALL_MPNET_BASE_V2: base(M.ALL_MPNET_BASE_V2), MULTI_QA_MINILM_L6_COS_V1: base(M.MULTI_QA_MINILM_L6_COS_V1), MULTI_QA_MPNET_BASE_DOT_V1: base(M.MULTI_QA_MPNET_BASE_DOT_V1), + DISTILUSE_BASE_MULTILINGUAL_CASED_V2: variant( + DISTILUSE_BASE_MULTILINGUAL_CASED_V2_VARIANTS, + COREML_ON_IOS + ), + /** + * @deprecated Use `DISTILUSE_BASE_MULTILINGUAL_CASED_V2` and either omit + * `backend` (defaults to xnnpack on Android) or pass `{ backend: 'xnnpack' }`. + */ DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W: base( M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W ), + /** + * @deprecated Use `DISTILUSE_BASE_MULTILINGUAL_CASED_V2({ backend: 'coreml' })`. + */ DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML: base( M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML ), diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index e82f764d36..283ad29f45 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -1179,6 +1179,8 @@ export const MULTI_QA_MPNET_BASE_DOT_V1 = { /** * @category Models - Text Embeddings + * @deprecated Use `MODEL_REGISTRY.TEXT_EMBEDDING.DISTILUSE_BASE_MULTILINGUAL_CASED_V2` + * (defaults to xnnpack on Android) or pass `{ backend: 'xnnpack' }`. */ export const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W = { modelName: 'distiluse-base-multilingual-cased-v2-8da4w', @@ -1188,6 +1190,7 @@ export const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W = { /** * @category Models - Text Embeddings + * @deprecated Use `MODEL_REGISTRY.TEXT_EMBEDDING.DISTILUSE_BASE_MULTILINGUAL_CASED_V2({ backend: 'coreml' })`. */ export const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML = { modelName: 'distiluse-base-multilingual-cased-v2-coreml', From fc5eeb02e829cd3030c467133ddcaa2ec3a3b251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Thu, 14 May 2026 11:17:10 +0200 Subject: [PATCH 07/16] feat(constants)!: default MODEL_REGISTRY accessors to the quantized variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bare accessors (and undefined `quant`) now resolve to the quantized variant when one is published; pass `{ quant: false }` to opt out. Docs and example apps are updated to match — dual pickers keep both rows by making the FP32 entry the explicit opt-out. --- apps/bare-rn/App.tsx | 2 +- .../app/classification/index.tsx | 6 +- .../app/segment_anything/index.tsx | 4 +- .../app/semantic_segmentation/index.tsx | 24 ++-- .../app/style_transfer/index.tsx | 19 +-- .../vision_camera/tasks/SegmentationTask.tsx | 20 +-- apps/llm/app/llm/index.tsx | 2 +- apps/llm/app/llm_structured_output/index.tsx | 2 +- apps/llm/app/llm_tool_calling/index.tsx | 2 +- apps/llm/app/voice_chat/index.tsx | 20 ++- apps/llm/components/llmModels.ts | 119 +++++++++++------- apps/speech/screens/SpeechToTextScreen.tsx | 6 +- .../app/clip-embeddings/index.tsx | 12 +- docs/docs/05-utilities/model-registry.md | 24 ++-- .../src/constants/modelRegistry.ts | 10 +- 15 files changed, 131 insertions(+), 141 deletions(-) diff --git a/apps/bare-rn/App.tsx b/apps/bare-rn/App.tsx index 116ddf87f5..d6575bee6a 100644 --- a/apps/bare-rn/App.tsx +++ b/apps/bare-rn/App.tsx @@ -145,7 +145,7 @@ function App() { const scrollViewRef = useRef(null); const llm = useLLM({ - model: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }), + model: MODEL_REGISTRY.LLM.LLAMA3_2_1B, }); // Alternatively, to use a custom local model, uncomment below: // const llm = useLLM({ model: { diff --git a/apps/computer-vision/app/classification/index.tsx b/apps/computer-vision/app/classification/index.tsx index 96c571376f..b1f4fe5d77 100644 --- a/apps/computer-vision/app/classification/index.tsx +++ b/apps/computer-vision/app/classification/index.tsx @@ -10,11 +10,11 @@ import { ModelPicker, ModelOption } from '../../components/ModelPicker'; const MODELS: ModelOption[] = [ { label: 'EfficientNet V2 S Quantized', - value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: true }), + value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S, }, { label: 'EfficientNet V2 S', - value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S, + value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: false }), }, ]; import { View, StyleSheet, Image, Text, ScrollView } from 'react-native'; @@ -28,7 +28,7 @@ import ErrorBanner from '../../components/ErrorBanner'; export default function ClassificationScreen() { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: true }) + MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S ); const [results, setResults] = useState<{ label: string; score: number }[]>( [] diff --git a/apps/computer-vision/app/segment_anything/index.tsx b/apps/computer-vision/app/segment_anything/index.tsx index 48c36e3feb..236951c3c4 100644 --- a/apps/computer-vision/app/segment_anything/index.tsx +++ b/apps/computer-vision/app/segment_anything/index.tsx @@ -77,9 +77,7 @@ export default function SegmentAnythingScreen() { useInstanceSegmentation({ model: selectedModel }); const clipImage = useImageEmbeddings({ - model: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ - quant: true, - }), + model: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE, }); const clipText = useTextEmbeddings({ model: MODEL_REGISTRY.TEXT_EMBEDDING.CLIP_VIT_BASE_PATCH32_TEXT, diff --git a/apps/computer-vision/app/semantic_segmentation/index.tsx b/apps/computer-vision/app/semantic_segmentation/index.tsx index cbbbdd2fb2..04d8f3b750 100644 --- a/apps/computer-vision/app/semantic_segmentation/index.tsx +++ b/apps/computer-vision/app/semantic_segmentation/index.tsx @@ -49,35 +49,27 @@ const numberToColor: number[][] = [ const MODELS: ModelOption[] = [ { label: 'DeepLab MobileNet', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE({ - quant: true, - }), + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE, }, { label: 'DeepLab ResNet50', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET50({ - quant: true, - }), + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET50, }, { label: 'DeepLab ResNet101', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET101({ - quant: true, - }), + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET101, }, { label: 'LRASPP MobileNet', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.LRASPP_MOBILENET_V3_LARGE({ - quant: true, - }), + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.LRASPP_MOBILENET_V3_LARGE, }, { label: 'FCN ResNet50', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET50({ quant: true }), + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET50, }, { label: 'FCN ResNet101', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET101({ quant: true }), + value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET101, }, { label: 'Selfie Segmentation', @@ -89,9 +81,7 @@ export default function SemanticSegmentationScreen() { const { setGlobalGenerating } = useContext(GeneratingContext); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE({ - quant: true, - }) + MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE ); const { diff --git a/apps/computer-vision/app/style_transfer/index.tsx b/apps/computer-vision/app/style_transfer/index.tsx index aac93360cf..ed1367202c 100644 --- a/apps/computer-vision/app/style_transfer/index.tsx +++ b/apps/computer-vision/app/style_transfer/index.tsx @@ -22,28 +22,19 @@ type StyleTransferModelSources = { }; const MODELS: ModelOption[] = [ - { - label: 'Candy', - value: MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ quant: true }), - }, - { - label: 'Mosaic', - value: MODEL_REGISTRY.STYLE_TRANSFER.MOSAIC({ quant: true }), - }, + { label: 'Candy', value: MODEL_REGISTRY.STYLE_TRANSFER.CANDY }, + { label: 'Mosaic', value: MODEL_REGISTRY.STYLE_TRANSFER.MOSAIC }, { label: 'Rain Princess', - value: MODEL_REGISTRY.STYLE_TRANSFER.RAIN_PRINCESS({ quant: true }), - }, - { - label: 'Udnie', - value: MODEL_REGISTRY.STYLE_TRANSFER.UDNIE({ quant: true }), + value: MODEL_REGISTRY.STYLE_TRANSFER.RAIN_PRINCESS, }, + { label: 'Udnie', value: MODEL_REGISTRY.STYLE_TRANSFER.UDNIE }, ]; import ErrorBanner from '../../components/ErrorBanner'; export default function StyleTransferScreen() { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ quant: true }) + MODEL_REGISTRY.STYLE_TRANSFER.CANDY ); const model = useStyleTransfer({ model: selectedModel }); diff --git a/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx b/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx index c46c924a02..601421d993 100644 --- a/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx @@ -41,35 +41,27 @@ export default function SegmentationTask({ onErrorChange, }: Props) { const segDeeplabResnet50 = useSemanticSegmentation({ - model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET50({ - quant: true, - }), + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET50, preventLoad: activeModel !== 'segmentationDeeplabResnet50', }); const segDeeplabResnet101 = useSemanticSegmentation({ - model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET101({ - quant: true, - }), + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET101, preventLoad: activeModel !== 'segmentationDeeplabResnet101', }); const segDeeplabMobilenet = useSemanticSegmentation({ - model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE({ - quant: true, - }), + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE, preventLoad: activeModel !== 'segmentationDeeplabMobilenet', }); const segLraspp = useSemanticSegmentation({ - model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.LRASPP_MOBILENET_V3_LARGE({ - quant: true, - }), + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.LRASPP_MOBILENET_V3_LARGE, preventLoad: activeModel !== 'segmentationLraspp', }); const segFcnResnet50 = useSemanticSegmentation({ - model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET50({ quant: true }), + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET50, preventLoad: activeModel !== 'segmentationFcnResnet50', }); const segFcnResnet101 = useSemanticSegmentation({ - model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET101({ quant: true }), + model: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET101, preventLoad: activeModel !== 'segmentationFcnResnet101', }); const segSelfie = useSemanticSegmentation({ diff --git a/apps/llm/app/llm/index.tsx b/apps/llm/app/llm/index.tsx index a31d7a6ff9..82f34cd288 100644 --- a/apps/llm/app/llm/index.tsx +++ b/apps/llm/app/llm/index.tsx @@ -43,7 +43,7 @@ function LLMScreen() { const [isTextInputFocused, setIsTextInputFocused] = useState(false); const [userInput, setUserInput] = useState(''); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }) + MODEL_REGISTRY.LLM.LLAMA3_2_1B ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/llm_structured_output/index.tsx b/apps/llm/app/llm_structured_output/index.tsx index b72defece4..b6eeadeb62 100644 --- a/apps/llm/app/llm_structured_output/index.tsx +++ b/apps/llm/app/llm_structured_output/index.tsx @@ -84,7 +84,7 @@ function LLMScreen() { const [isTextInputFocused, setIsTextInputFocused] = useState(false); const [userInput, setUserInput] = useState(''); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: true }) + MODEL_REGISTRY.LLM.QWEN3_1_7B ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/llm_tool_calling/index.tsx b/apps/llm/app/llm_tool_calling/index.tsx index 59388ce76e..19b2ece57b 100644 --- a/apps/llm/app/llm_tool_calling/index.tsx +++ b/apps/llm/app/llm_tool_calling/index.tsx @@ -55,7 +55,7 @@ function LLMToolCallingScreen() { const [hasCalendarPermission, setHasCalendarPermission] = useState(true); const [hasBrightnessPermission, setHasBrightnessPermission] = useState(true); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.LLM.HAMMER2_1_1_5B({ quant: true }) + MODEL_REGISTRY.LLM.HAMMER2_1_1_5B ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/voice_chat/index.tsx b/apps/llm/app/voice_chat/index.tsx index 991031afa3..a485aa33d5 100644 --- a/apps/llm/app/voice_chat/index.tsx +++ b/apps/llm/app/voice_chat/index.tsx @@ -35,25 +35,19 @@ type LLMModelSources = LLMProps['model']; type STTModelSources = SpeechToTextProps['model']; const LLM_MODELS: ModelOption[] = [ - { - label: 'Qwen3 0.6B', - value: MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: true }), - }, - { - label: 'Qwen3 1.7B', - value: MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: true }), - }, - { label: 'Llama 1B', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }) }, + { label: 'Qwen3 0.6B', value: MODEL_REGISTRY.LLM.QWEN3_0_6B }, + { label: 'Qwen3 1.7B', value: MODEL_REGISTRY.LLM.QWEN3_1_7B }, + { label: 'Llama 1B', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B }, ]; const STT_MODELS: ModelOption[] = [ { label: 'Whisper Tiny', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }), }, { label: 'Whisper Tiny Q', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: true }), + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, }, { label: 'Whisper Base', @@ -76,10 +70,10 @@ function VoiceChatScreen() { const [isRecording, setIsRecording] = useState(false); const [liveTranscription, setLiveTranscription] = useState(''); const [selectedLLM, setSelectedLLM] = useState( - MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: true }) + MODEL_REGISTRY.LLM.QWEN3_0_6B ); const [selectedSTT, setSelectedSTT] = useState( - MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN + MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }) ); const [error, setError] = useState(null); diff --git a/apps/llm/components/llmModels.ts b/apps/llm/components/llmModels.ts index de42f72ed9..216f5277b0 100644 --- a/apps/llm/components/llmModels.ts +++ b/apps/llm/components/llmModels.ts @@ -10,109 +10,136 @@ export type LLMModelSources = LLMProps['model']; export const LLM_MODELS: ModelOption[] = [ // Llama 3.2 - { label: 'Llama 3.2 1B', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B }, - { label: 'Llama 3.2 1B QLoRA', value: LLAMA3_2_1B_QLORA }, { - label: 'Llama 3.2 1B SpinQuant', - value: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: true }), + label: 'Llama 3.2 1B', + value: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: false }), }, - { label: 'Llama 3.2 3B', value: MODEL_REGISTRY.LLM.LLAMA3_2_3B }, - { label: 'Llama 3.2 3B QLoRA', value: LLAMA3_2_3B_QLORA }, + { label: 'Llama 3.2 1B QLoRA', value: LLAMA3_2_1B_QLORA }, + { label: 'Llama 3.2 1B SpinQuant', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B }, { - label: 'Llama 3.2 3B SpinQuant', - value: MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true }), + label: 'Llama 3.2 3B', + value: MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false }), }, + { label: 'Llama 3.2 3B QLoRA', value: LLAMA3_2_3B_QLORA }, + { label: 'Llama 3.2 3B SpinQuant', value: MODEL_REGISTRY.LLM.LLAMA3_2_3B }, // Qwen3 - { label: 'Qwen3 0.6B', value: MODEL_REGISTRY.LLM.QWEN3_0_6B }, { - label: 'Qwen3 0.6B Quantized', - value: MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: true }), + label: 'Qwen3 0.6B', + value: MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: false }), }, - { label: 'Qwen3 1.7B', value: MODEL_REGISTRY.LLM.QWEN3_1_7B }, + { label: 'Qwen3 0.6B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_0_6B }, { - label: 'Qwen3 1.7B Quantized', - value: MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: true }), + label: 'Qwen3 1.7B', + value: MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: false }), }, - { label: 'Qwen3 4B', value: MODEL_REGISTRY.LLM.QWEN3_4B }, + { label: 'Qwen3 1.7B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_1_7B }, + { label: 'Qwen3 4B', value: MODEL_REGISTRY.LLM.QWEN3_4B({ quant: false }) }, + { label: 'Qwen3 4B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_4B }, + // Hammer 2.1 { - label: 'Qwen3 4B Quantized', - value: MODEL_REGISTRY.LLM.QWEN3_4B({ quant: true }), + label: 'Hammer 2.1 0.5B', + value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B({ quant: false }), }, - // Hammer 2.1 - { label: 'Hammer 2.1 0.5B', value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B }, { label: 'Hammer 2.1 0.5B Quantized', - value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B({ quant: true }), + value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B, + }, + { + label: 'Hammer 2.1 1.5B', + value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B({ quant: false }), }, - { label: 'Hammer 2.1 1.5B', value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B }, { label: 'Hammer 2.1 1.5B Quantized', - value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B({ quant: true }), + value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B, + }, + { + label: 'Hammer 2.1 3B', + value: MODEL_REGISTRY.LLM.HAMMER2_1_3B({ quant: false }), }, - { label: 'Hammer 2.1 3B', value: MODEL_REGISTRY.LLM.HAMMER2_1_3B }, { label: 'Hammer 2.1 3B Quantized', - value: MODEL_REGISTRY.LLM.HAMMER2_1_3B({ quant: true }), + value: MODEL_REGISTRY.LLM.HAMMER2_1_3B, }, // SmolLM2 - { label: 'SmolLM2 135M', value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M }, + { + label: 'SmolLM2 135M', + value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M({ quant: false }), + }, { label: 'SmolLM2 135M Quantized', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M({ quant: true }), + value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M, + }, + { + label: 'SmolLM2 360M', + value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M({ quant: false }), }, - { label: 'SmolLM2 360M', value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M }, { label: 'SmolLM2 360M Quantized', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M({ quant: true }), + value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M, + }, + { + label: 'SmolLM2 1.7B', + value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B({ quant: false }), }, - { label: 'SmolLM2 1.7B', value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B }, { label: 'SmolLM2 1.7B Quantized', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B({ quant: true }), + value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B, }, // Qwen2.5 - { label: 'Qwen2.5 0.5B', value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B }, + { + label: 'Qwen2.5 0.5B', + value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B({ quant: false }), + }, { label: 'Qwen2.5 0.5B Quantized', - value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B({ quant: true }), + value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B, + }, + { + label: 'Qwen2.5 1.5B', + value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B({ quant: false }), }, - { label: 'Qwen2.5 1.5B', value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B }, { label: 'Qwen2.5 1.5B Quantized', - value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B({ quant: true }), + value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B, }, - { label: 'Qwen2.5 3B', value: MODEL_REGISTRY.LLM.QWEN2_5_3B }, { - label: 'Qwen2.5 3B Quantized', - value: MODEL_REGISTRY.LLM.QWEN2_5_3B({ quant: true }), + label: 'Qwen2.5 3B', + value: MODEL_REGISTRY.LLM.QWEN2_5_3B({ quant: false }), }, + { label: 'Qwen2.5 3B Quantized', value: MODEL_REGISTRY.LLM.QWEN2_5_3B }, // Qwen3.5 { label: 'Qwen3.5 0.8B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_5_0_8B }, { label: 'Qwen3.5 2B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_5_2B }, // Phi-4 - { label: 'Phi-4 Mini 4B', value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B }, + { + label: 'Phi-4 Mini 4B', + value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B({ quant: false }), + }, { label: 'Phi-4 Mini 4B Quantized', - value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B({ quant: true }), + value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B, }, // LFM2.5 - { label: 'LFM2.5 350M', value: MODEL_REGISTRY.LLM.LFM2_5_350M }, { - label: 'LFM2.5 350M Quantized', - value: MODEL_REGISTRY.LLM.LFM2_5_350M({ quant: true }), + label: 'LFM2.5 350M', + value: MODEL_REGISTRY.LLM.LFM2_5_350M({ quant: false }), }, + { label: 'LFM2.5 350M Quantized', value: MODEL_REGISTRY.LLM.LFM2_5_350M }, { label: 'LFM2.5 1.2B Instruct', - value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT, + value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT({ quant: false }), }, { label: 'LFM2.5 1.2B Instruct Quantized', - value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT({ quant: true }), + value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT, }, // Bielik v3.0 - { label: 'Bielik v3.0 1.5B', value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B }, + { + label: 'Bielik v3.0 1.5B', + value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B({ quant: false }), + }, { label: 'Bielik v3.0 1.5B Quantized', - value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B({ quant: true }), + value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B, }, ]; diff --git a/apps/speech/screens/SpeechToTextScreen.tsx b/apps/speech/screens/SpeechToTextScreen.tsx index a1d5997d54..2d255ca741 100644 --- a/apps/speech/screens/SpeechToTextScreen.tsx +++ b/apps/speech/screens/SpeechToTextScreen.tsx @@ -24,11 +24,11 @@ type STTModelSources = SpeechToTextProps['model']; const MODELS: ModelOption[] = [ { label: 'Whisper Tiny', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }), }, { label: 'Whisper Tiny Q', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: true }), + value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, }, { label: 'Whisper Base', @@ -56,7 +56,7 @@ const isSimulator = DeviceInfo.isEmulatorSync(); export const SpeechToTextScreen = ({ onBack }: { onBack: () => void }) => { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN + MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }) ); const model = useSpeechToText({ diff --git a/apps/text-embeddings/app/clip-embeddings/index.tsx b/apps/text-embeddings/app/clip-embeddings/index.tsx index 77f2516c02..7e3f173f5e 100644 --- a/apps/text-embeddings/app/clip-embeddings/index.tsx +++ b/apps/text-embeddings/app/clip-embeddings/index.tsx @@ -24,13 +24,13 @@ type ImageEmbeddingModel = ImageEmbeddingsProps['model']; const IMAGE_MODELS: { label: string; value: ImageEmbeddingModel }[] = [ { label: 'ViT-B/32 Quantized', - value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ - quant: true, - }), + value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE, }, { label: 'ViT-B/32 FP32', - value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE, + value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ + quant: false, + }), }, ]; import { launchImageLibrary } from 'react-native-image-picker'; @@ -55,9 +55,7 @@ export default function ClipEmbeddingsScreenWrapper() { function ClipEmbeddingsScreen() { const [selectedImageModel, setSelectedImageModel] = useState( - MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ - quant: true, - }) + MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE ); const textModel = useTextEmbeddings({ diff --git a/docs/docs/05-utilities/model-registry.md b/docs/docs/05-utilities/model-registry.md index 0f870a7c52..4a2c5adb2d 100644 --- a/docs/docs/05-utilities/model-registry.md +++ b/docs/docs/05-utilities/model-registry.md @@ -2,16 +2,16 @@ title: Model Registry --- -The [Model Registry](/react-native-executorch/docs/next/api-reference/variables/MODEL_REGISTRY) is a typed, grouped index of every model shipped with React Native ExecuTorch. It removes the need to memorize per-model constant names: pick a capability group, pick a model, and optionally request its quantized variant. +The [Model Registry](/react-native-executorch/docs/next/api-reference/variables/MODEL_REGISTRY) is a typed, grouped index of every model shipped with React Native ExecuTorch. It removes the need to memorize per-model constant names: pick a capability group, pick a model, and optionally opt out of quantization. ```typescript import { MODEL_REGISTRY } from 'react-native-executorch'; -// Default (non-quantized, platform-default backend). +// Default (quantized when available, platform-default backend). const llm = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B); -// Quantized variant. -const llmQuant = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })); +// Non-quantized variant. +const llmBase = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false })); ``` ## Shape @@ -37,12 +37,12 @@ const llmQuant = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })); ```typescript type ModelOpts = { - quant?: boolean; // Pick the quantized variant when true. Ignored when no quantized variant exists. + quant?: boolean; // Pick the non-quantized variant when false. Defaults to the quantized variant when one is published. backend?: B; // Explicit backend; the set of allowed values is per-model. }; ``` -- `quant: true` resolves to the quantized variant for models that publish one (e.g. `LLAMA3_2_3B` → SpinQuant, `EFFICIENTNET_V2_S` → int8). For models with a single variant, `quant` is accepted but has no effect. +- `quant` defaults to the quantized variant for models that publish one (e.g. `LLAMA3_2_3B` → SpinQuant, `EFFICIENTNET_V2_S` → int8). Pass `{ quant: false }` to get the full-precision variant. For models with a single variant, `quant` is accepted but has no effect. - `backend` selects an explicit backend. The accessor's call signature is typed to exactly the backends the model ships with, so requesting one the model doesn't publish is a compile-time error (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ backend: 'coreml' })` does not type-check — Llama 3.2 is xnnpack-only). When `backend` is omitted, the platform-default applies (typically CoreML on iOS and XNNPACK on Android for multi-backend models). ## Usage patterns @@ -61,12 +61,12 @@ const speechToText = useSpeechToText( ); ``` -### Quantized variant +### Non-quantized variant ```typescript -const llm = useLLM(MODEL_REGISTRY.LLM.QWEN3_4B({ quant: true })); +const llm = useLLM(MODEL_REGISTRY.LLM.QWEN3_4B({ quant: false })); const classifier = useClassification( - MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: true }) + MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: false }) ); ``` @@ -80,7 +80,7 @@ const detector = useObjectDetection({ // Combine `quant` and `backend`. const styled = useStyleTransfer( - MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ backend: 'coreml', quant: true }) + MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ backend: 'coreml', quant: false }) ); ``` @@ -90,10 +90,10 @@ Accessors transparently expose the default config's fields, so you can read them ```typescript console.log(MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelName); -// → "llama-3.2-3b" +// → "llama-3.2-3b-spinquant" console.log(MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelSource); -// → "https://huggingface.co/software-mansion/react-native-executorch-llama-3.2/resolve/v0.9.0/3b/xnnpack/llama_3_2_3b_xnnpack_bf16.pte" +// → "https://huggingface.co/software-mansion/react-native-executorch-llama-3.2/resolve/v0.9.0/3b/xnnpack/llama_3_2_3b_xnnpack_spinquant.pte" ``` ### Direct imports still work diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts index 45dd344cce..b26598c9d4 100644 --- a/packages/react-native-executorch/src/constants/modelRegistry.ts +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -20,7 +20,7 @@ export type Backend = 'xnnpack' | 'coreml' | 'vulkan' | 'qnn'; * @category Utils */ export type ModelOpts = { - /** Pick the quantized variant when `true`. Ignored when a quantized variant is not published. */ + /** Pick the non-quantized variant when `false`. Defaults to the quantized variant when one is published. */ quant?: boolean; /** Explicit backend; defaults to the platform-preferred backend for the model. */ backend?: B; @@ -29,7 +29,7 @@ export type ModelOpts = { /** * An accessor that behaves as the platform-default config when read as a value * (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelName`) and as a function when - * called (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })`). + * called (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false })`). */ type Accessor< C extends { modelName: string }, @@ -105,7 +105,7 @@ function resolveVariant( if (!cell) { throw new Error(`Backend '${backend}' is not available for this model.`); } - return resolveCell(cell, opts.quant === true); + return resolveCell(cell, opts.quant !== false); } // Build an Accessor from a per-backend variant map and an optional @@ -334,8 +334,8 @@ const COREML_ON_IOS = { ios: 'coreml', default: 'xnnpack' } as const; * model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO({ backend: 'xnnpack' }), * }); * - * // Quantized variant. - * useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: true })); + * // Non-quantized variant. + * useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false })); * ``` * @category Utils */ From d0982df70b947cc3bdd726c2e2350d6724ba800c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Thu, 14 May 2026 14:51:56 +0200 Subject: [PATCH 08/16] fix(constants): align URLs with v0.9.0 HF incompat fixes Each repo's v0.9.0 tag was retagged or rewritten today to match MODEL_SPEC.md. Sync the constants: - clip-vit-base-patch32: image/text encoders now live under their component-tokenized filenames (the migration silently dropped text and pointed both image and text constants at the image encoder). - deeplab-v3, fcn: separate filenames per backbone (mobilenet_v3_large, resnet50, resnet101 for deeplab; resnet50, resnet101 for fcn). All three deeplab constants previously resolved to the same blob. - fast-sam: size-tokened paths (S vs X) for both xnnpack and coreml. FASTSAM_S and FASTSAM_X were aliased to the X variant. - qwen-3.5: tokenizers moved out of the legacy Qwen3.5-{0.8B,2B}/ directories into the canonical / layout matching lfm-2.5. --- .../src/constants/modelRegistry.ts | 8 ++-- .../src/constants/modelUrls.ts | 42 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts index b26598c9d4..40c25f9d9d 100644 --- a/packages/react-native-executorch/src/constants/modelRegistry.ts +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -218,13 +218,13 @@ const FASTSAM_S_VARIANTS = { xnnpack: { default: { modelName: 'fastsam-s' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_s_xnnpack_fp32.pte`, }, }, coreml: { default: { modelName: 'fastsam-s' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_s_coreml_fp16.pte`, }, }, }; @@ -233,13 +233,13 @@ const FASTSAM_X_VARIANTS = { xnnpack: { default: { modelName: 'fastsam-x' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_x_xnnpack_fp32.pte`, }, }, coreml: { default: { modelName: 'fastsam-x' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_x_coreml_fp16.pte`, }, }, }; diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index 283ad29f45..bbfa0a951e 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -381,8 +381,8 @@ export const QWEN2_5_3B_QUANTIZED = { // QWEN3.5-0.8B const QWEN3_5_0_8B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/0_8b/xnnpack/qwen_3_5_0_8b_xnnpack_8da4w.pte`; -const QWEN3_5_0_8B_TOKENIZER = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-0.8B/tokenizer.json`; -const QWEN3_5_0_8B_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-0.8B/tokenizer_config.json`; +const QWEN3_5_0_8B_TOKENIZER = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/0_8b/tokenizer.json`; +const QWEN3_5_0_8B_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/0_8b/tokenizer_config.json`; /** * @category Models - LLM @@ -396,8 +396,8 @@ export const QWEN3_5_0_8B_QUANTIZED = { // QWEN3.5-2B const QWEN3_5_2B_QUANTIZED_MODEL = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/2b/xnnpack/qwen_3_5_2b_xnnpack_8da4w.pte`; -const QWEN3_5_2B_TOKENIZER = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-2B/tokenizer.json`; -const QWEN3_5_2B_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/Qwen3.5-2B/tokenizer_config.json`; +const QWEN3_5_2B_TOKENIZER = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/2b/tokenizer.json`; +const QWEN3_5_2B_TOKENIZER_CONFIG = `${URL_PREFIX}-qwen-3.5/${VERSION_TAG}/2b/tokenizer_config.json`; /** * @category Models - LLM @@ -899,18 +899,18 @@ export const WHISPER_SMALL = { } as const; // Semantic Segmentation -const DEEPLAB_V3_RESNET50_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_fp32.pte`; -const DEEPLAB_V3_RESNET101_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_fp32.pte`; -const DEEPLAB_V3_MOBILENET_V3_LARGE_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_fp32.pte`; +const DEEPLAB_V3_RESNET50_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_resnet50_xnnpack_fp32.pte`; +const DEEPLAB_V3_RESNET101_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_resnet101_xnnpack_fp32.pte`; +const DEEPLAB_V3_MOBILENET_V3_LARGE_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_mobilenet_v3_large_xnnpack_fp32.pte`; const LRASPP_MOBILENET_V3_LARGE_MODEL = `${URL_PREFIX}-lraspp/${VERSION_TAG}/xnnpack/lraspp_mobilenet_v3_large_xnnpack_fp32.pte`; -const FCN_RESNET50_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_fp32.pte`; -const FCN_RESNET101_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_fp32.pte`; -const DEEPLAB_V3_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_int8.pte`; -const DEEPLAB_V3_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_int8.pte`; -const DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_xnnpack_int8.pte`; +const FCN_RESNET50_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_resnet50_xnnpack_fp32.pte`; +const FCN_RESNET101_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_resnet101_xnnpack_fp32.pte`; +const DEEPLAB_V3_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_resnet50_xnnpack_int8.pte`; +const DEEPLAB_V3_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_resnet101_xnnpack_int8.pte`; +const DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED_MODEL = `${URL_PREFIX}-deeplab-v3/${VERSION_TAG}/xnnpack/deeplab_v3_mobilenet_v3_large_xnnpack_int8.pte`; const LRASPP_MOBILENET_V3_LARGE_QUANTIZED_MODEL = `${URL_PREFIX}-lraspp/${VERSION_TAG}/xnnpack/lraspp_mobilenet_v3_large_xnnpack_int8.pte`; -const FCN_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_int8.pte`; -const FCN_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_xnnpack_int8.pte`; +const FCN_RESNET50_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_resnet50_xnnpack_int8.pte`; +const FCN_RESNET101_QUANTIZED_MODEL = `${URL_PREFIX}-fcn/${VERSION_TAG}/xnnpack/fcn_resnet101_xnnpack_int8.pte`; /** * @category Models - Semantic Segmentation @@ -1021,12 +1021,12 @@ export const SELFIE_SEGMENTATION = { // FastSAM Instance Segmentation const FASTSAM_S_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_s_coreml_fp16.pte` + : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_s_xnnpack_fp32.pte`; const FASTSAM_X_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_x_coreml_fp16.pte` + : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_x_xnnpack_fp32.pte`; /** * @category Models - Instance Segmentation @@ -1105,8 +1105,8 @@ export const RF_DETR_NANO_SEG = { } as const; // Image Embeddings -const CLIP_VIT_BASE_PATCH32_IMAGE_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_xnnpack_fp32.pte`; -const CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_xnnpack_int8.pte`; +const CLIP_VIT_BASE_PATCH32_IMAGE_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_image_xnnpack_fp32.pte`; +const CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_image_xnnpack_int8.pte`; /** * @category Models - Image Embeddings @@ -1138,7 +1138,7 @@ const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML_MODEL = `${URL_PREFIX}-distilu const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_TOKENIZER = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/tokenizer.json`; const PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED_MODEL = `${URL_PREFIX}-paraphrase-multilingual-MiniLM-L12-v2/${VERSION_TAG}/xnnpack/paraphrase_multilingual_minilm_l12_v2_xnnpack_8da4w.pte`; const PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_TOKENIZER = `${URL_PREFIX}-paraphrase-multilingual-MiniLM-L12-v2/${VERSION_TAG}/tokenizer.json`; -const CLIP_VIT_BASE_PATCH32_TEXT_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_xnnpack_fp32.pte`; +const CLIP_VIT_BASE_PATCH32_TEXT_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_text_xnnpack_fp32.pte`; const CLIP_VIT_BASE_PATCH32_TEXT_TOKENIZER = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/tokenizer.json`; /** From d849b0a80bc00b747282cc88c8fbd0f56b782058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Thu, 14 May 2026 15:21:38 +0200 Subject: [PATCH 09/16] refactor(constants): rename BackendCell `default` -> `base`; fast-sam size-first paths `MODEL_REGISTRY` accessors default to the quantized variant when one is published, so the non-quantized slot is no longer the runtime default. Rename the `BackendCell.default` key to `base` so the field name matches what it actually represents (the unquantized base variant) and stops fighting the new runtime default. `PlatformDefaults.default` is unrelated (platform-fallback backend) and is unchanged. Also point FastSAM URLs at the size-first HF layout: //fast_sam___.pte matching the yolo26-seg / lfm-2.5 convention. --- .../src/constants/modelRegistry.ts | 56 +++++++++---------- .../src/constants/modelUrls.ts | 8 +-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts index 40c25f9d9d..0c1e011248 100644 --- a/packages/react-native-executorch/src/constants/modelRegistry.ts +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -37,7 +37,7 @@ type Accessor< > = C & ((opts?: ModelOpts) => C); type BackendCell = { - default?: { modelName: string }; + base?: { modelName: string }; quant?: { modelName: string }; }; type AnyVariantMap = Partial>; @@ -48,7 +48,7 @@ type PlatformDefaults = { default?: B; }; -type CellConfig = T extends { default?: infer D; quant?: infer Q } +type CellConfig = T extends { base?: infer D; quant?: infer Q } ? NonNullable | NonNullable : never; type ConfigOf = Extract< @@ -86,8 +86,8 @@ function resolveBackend( function resolveCell(cell: BackendCell, quant: boolean): { modelName: string } { // Fall back to the other slot when the requested precision is missing, // so single-precision backends still work either way. - const primary = quant ? cell.quant : cell.default; - const fallback = quant ? cell.default : cell.quant; + const primary = quant ? cell.quant : cell.base; + const fallback = quant ? cell.base : cell.quant; const result = primary ?? fallback; if (!result) { throw new Error('Model variant cell has no config.'); @@ -126,15 +126,15 @@ function variant( // Single-config accessor (xnnpack-only, no quantized variant). function base(c: C) { - return variant({ xnnpack: { default: c } }); + return variant({ xnnpack: { base: c } }); } -// xnnpack-only accessor with a `default` / `quant` pair. +// xnnpack-only accessor with a `base` / `quant` pair. function pair( - defaultC: D, + baseC: D, quantC: Q ) { - return variant({ xnnpack: { default: defaultC, quant: quantC } }); + return variant({ xnnpack: { base: baseC, quant: quantC } }); } // ───────────────────────────────────────────────────────────────────────────── @@ -148,7 +148,7 @@ function pair( const EFFICIENTNET_V2_S_VARIANTS = { xnnpack: { - default: { + base: { modelName: 'efficientnet-v2-s' as const, modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_fp32.pte`, }, @@ -158,7 +158,7 @@ const EFFICIENTNET_V2_S_VARIANTS = { }, }, coreml: { - default: { + base: { modelName: 'efficientnet-v2-s' as const, modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp32.pte`, }, @@ -171,13 +171,13 @@ const EFFICIENTNET_V2_S_VARIANTS = { const SSDLITE_320_MOBILENET_V3_LARGE_VARIANTS = { xnnpack: { - default: { + base: { modelName: 'ssdlite-320-mobilenet-v3-large' as const, modelSource: `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/xnnpack/ssdlite320_mobilenet_v3_large_xnnpack_fp32.pte`, }, }, coreml: { - default: { + base: { modelName: 'ssdlite-320-mobilenet-v3-large' as const, modelSource: `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/coreml/ssdlite320_mobilenet_v3_large_coreml_fp16.pte`, }, @@ -186,13 +186,13 @@ const SSDLITE_320_MOBILENET_V3_LARGE_VARIANTS = { const RF_DETR_NANO_VARIANTS = { xnnpack: { - default: { + base: { modelName: 'rf-detr-nano' as const, modelSource: `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`, }, }, coreml: { - default: { + base: { modelName: 'rf-detr-nano' as const, modelSource: `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`, }, @@ -201,13 +201,13 @@ const RF_DETR_NANO_VARIANTS = { const RF_DETR_NANO_SEG_VARIANTS = { xnnpack: { - default: { + base: { modelName: 'rfdetr-nano-seg' as const, modelSource: `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`, }, }, coreml: { - default: { + base: { modelName: 'rfdetr-nano-seg' as const, modelSource: `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`, }, @@ -216,30 +216,30 @@ const RF_DETR_NANO_SEG_VARIANTS = { const FASTSAM_S_VARIANTS = { xnnpack: { - default: { + base: { modelName: 'fastsam-s' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_s_xnnpack_fp32.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/xnnpack/fast_sam_s_xnnpack_fp32.pte`, }, }, coreml: { - default: { + base: { modelName: 'fastsam-s' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_s_coreml_fp16.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/coreml/fast_sam_s_coreml_fp16.pte`, }, }, }; const FASTSAM_X_VARIANTS = { xnnpack: { - default: { + base: { modelName: 'fastsam-x' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_x_xnnpack_fp32.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/xnnpack/fast_sam_x_xnnpack_fp32.pte`, }, }, coreml: { - default: { + base: { modelName: 'fastsam-x' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_x_coreml_fp16.pte`, + modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/coreml/fast_sam_x_coreml_fp16.pte`, }, }, }; @@ -250,7 +250,7 @@ function styleTransferVariants< >(display: Display, slug: Slug) { return { xnnpack: { - default: { + base: { modelName: `style-transfer-${display}`, modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/xnnpack/style_transfer_${slug}_xnnpack_fp32.pte`, } as { @@ -266,7 +266,7 @@ function styleTransferVariants< }, }, coreml: { - default: { + base: { modelName: `style-transfer-${display}`, modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/coreml/style_transfer_${slug}_coreml_fp32.pte`, } as { @@ -299,14 +299,14 @@ const DISTILUSE_TOKENIZER = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/ const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_VARIANTS = { xnnpack: { - default: { + base: { modelName: 'distiluse-base-multilingual-cased-v2-8da4w' as const, modelSource: `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/xnnpack/distiluse_base_multilingual_cased_v2_xnnpack_8da4w.pte`, tokenizerSource: DISTILUSE_TOKENIZER, }, }, coreml: { - default: { + base: { modelName: 'distiluse-base-multilingual-cased-v2-coreml' as const, modelSource: `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/coreml/distiluse_base_multilingual_cased_v2_coreml_fp32.pte`, tokenizerSource: DISTILUSE_TOKENIZER, diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index bbfa0a951e..e18947deab 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -1021,12 +1021,12 @@ export const SELFIE_SEGMENTATION = { // FastSAM Instance Segmentation const FASTSAM_S_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_s_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_s_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/coreml/fast_sam_s_coreml_fp16.pte` + : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/xnnpack/fast_sam_s_xnnpack_fp32.pte`; const FASTSAM_X_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/coreml/fast_sam_x_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/xnnpack/fast_sam_x_xnnpack_fp32.pte`; + ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/coreml/fast_sam_x_coreml_fp16.pte` + : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/xnnpack/fast_sam_x_xnnpack_fp32.pte`; /** * @category Models - Instance Segmentation From 7086044a65e6f00ff8e5143a0044411091cb1df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Mon, 18 May 2026 09:31:20 +0200 Subject: [PATCH 10/16] refactor(constants): hoist multi-backend URLs to modelUrls.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit modelRegistry.ts duplicated the same `${URL_PREFIX}-…/${VERSION_TAG}/…` strings that modelUrls.ts already had inline in each Platform.OS branch. Hoist a single set of per-backend URL constants into modelUrls.ts and have both consumers reference them, so each URL string lives in exactly one place. - Add per-backend exports for efficientnet-v2-s, ssdlite320-mobilenet-v3- large, rfdetr-nano-detector, rfdetr-nano-segmentation, fast-sam {s,x}, distiluse-base-multilingual-cased-v2. - Add `styleTransferUrls(display, slug)` helper for the 4 style-transfer styles; the registry's `styleTransferVariants` now consumes it. - Drop the now-unused `URL_PREFIX, VERSION_TAG` import from modelRegistry.ts. Addresses https://github.com/software-mansion/react-native-executorch/pull/1148#discussion_r3241855656 --- .../src/constants/modelRegistry.ts | 48 ++++----- .../src/constants/modelUrls.ts | 101 ++++++++++-------- 2 files changed, 81 insertions(+), 68 deletions(-) diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts index 0c1e011248..1120b1992c 100644 --- a/packages/react-native-executorch/src/constants/modelRegistry.ts +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -1,6 +1,5 @@ import { Platform } from 'react-native'; import * as M from './modelUrls'; -import { URL_PREFIX, VERSION_TAG } from './versions'; /** * Backend options accepted by `MODEL_REGISTRY` accessors. @@ -150,21 +149,21 @@ const EFFICIENTNET_V2_S_VARIANTS = { xnnpack: { base: { modelName: 'efficientnet-v2-s' as const, - modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_fp32.pte`, + modelSource: M.EFFICIENTNET_V2_S_XNNPACK_FP32_MODEL, }, quant: { modelName: 'efficientnet-v2-s-quantized' as const, - modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_int8.pte`, + modelSource: M.EFFICIENTNET_V2_S_XNNPACK_INT8_MODEL, }, }, coreml: { base: { modelName: 'efficientnet-v2-s' as const, - modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp32.pte`, + modelSource: M.EFFICIENTNET_V2_S_COREML_FP32_MODEL, }, quant: { modelName: 'efficientnet-v2-s-quantized' as const, - modelSource: `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp16.pte`, + modelSource: M.EFFICIENTNET_V2_S_COREML_FP16_MODEL, }, }, }; @@ -173,13 +172,13 @@ const SSDLITE_320_MOBILENET_V3_LARGE_VARIANTS = { xnnpack: { base: { modelName: 'ssdlite-320-mobilenet-v3-large' as const, - modelSource: `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/xnnpack/ssdlite320_mobilenet_v3_large_xnnpack_fp32.pte`, + modelSource: M.SSDLITE_320_MOBILENET_V3_LARGE_XNNPACK_FP32_MODEL, }, }, coreml: { base: { modelName: 'ssdlite-320-mobilenet-v3-large' as const, - modelSource: `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/coreml/ssdlite320_mobilenet_v3_large_coreml_fp16.pte`, + modelSource: M.SSDLITE_320_MOBILENET_V3_LARGE_COREML_FP16_MODEL, }, }, }; @@ -188,13 +187,13 @@ const RF_DETR_NANO_VARIANTS = { xnnpack: { base: { modelName: 'rf-detr-nano' as const, - modelSource: `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`, + modelSource: M.RF_DETR_NANO_XNNPACK_FP32_MODEL, }, }, coreml: { base: { modelName: 'rf-detr-nano' as const, - modelSource: `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`, + modelSource: M.RF_DETR_NANO_COREML_INT8_MODEL, }, }, }; @@ -203,13 +202,13 @@ const RF_DETR_NANO_SEG_VARIANTS = { xnnpack: { base: { modelName: 'rfdetr-nano-seg' as const, - modelSource: `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`, + modelSource: M.RF_DETR_NANO_SEG_XNNPACK_FP32_MODEL, }, }, coreml: { base: { modelName: 'rfdetr-nano-seg' as const, - modelSource: `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`, + modelSource: M.RF_DETR_NANO_SEG_COREML_INT8_MODEL, }, }, }; @@ -218,13 +217,13 @@ const FASTSAM_S_VARIANTS = { xnnpack: { base: { modelName: 'fastsam-s' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/xnnpack/fast_sam_s_xnnpack_fp32.pte`, + modelSource: M.FASTSAM_S_XNNPACK_FP32_MODEL, }, }, coreml: { base: { modelName: 'fastsam-s' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/coreml/fast_sam_s_coreml_fp16.pte`, + modelSource: M.FASTSAM_S_COREML_FP16_MODEL, }, }, }; @@ -233,13 +232,13 @@ const FASTSAM_X_VARIANTS = { xnnpack: { base: { modelName: 'fastsam-x' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/xnnpack/fast_sam_x_xnnpack_fp32.pte`, + modelSource: M.FASTSAM_X_XNNPACK_FP32_MODEL, }, }, coreml: { base: { modelName: 'fastsam-x' as const, - modelSource: `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/coreml/fast_sam_x_coreml_fp16.pte`, + modelSource: M.FASTSAM_X_COREML_FP16_MODEL, }, }, }; @@ -248,18 +247,19 @@ function styleTransferVariants< const Display extends string, const Slug extends string, >(display: Display, slug: Slug) { + const urls = M.styleTransferUrls(display, slug); return { xnnpack: { base: { modelName: `style-transfer-${display}`, - modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/xnnpack/style_transfer_${slug}_xnnpack_fp32.pte`, + modelSource: urls.xnnpackBase, } as { modelName: `style-transfer-${Display}`; modelSource: string; }, quant: { modelName: `style-transfer-${display}-quantized`, - modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/xnnpack/style_transfer_${slug}_xnnpack_int8.pte`, + modelSource: urls.xnnpackQuant, } as { modelName: `style-transfer-${Display}-quantized`; modelSource: string; @@ -268,14 +268,14 @@ function styleTransferVariants< coreml: { base: { modelName: `style-transfer-${display}`, - modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/coreml/style_transfer_${slug}_coreml_fp32.pte`, + modelSource: urls.coremlBase, } as { modelName: `style-transfer-${Display}`; modelSource: string; }, quant: { modelName: `style-transfer-${display}-quantized`, - modelSource: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/coreml/style_transfer_${slug}_coreml_fp16.pte`, + modelSource: urls.coremlQuant, } as { modelName: `style-transfer-${Display}-quantized`; modelSource: string; @@ -295,21 +295,19 @@ const STYLE_TRANSFER_RAIN_PRINCESS_VARIANTS = styleTransferVariants( ); const STYLE_TRANSFER_UDNIE_VARIANTS = styleTransferVariants('udnie', 'udnie'); -const DISTILUSE_TOKENIZER = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/tokenizer.json`; - const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_VARIANTS = { xnnpack: { base: { modelName: 'distiluse-base-multilingual-cased-v2-8da4w' as const, - modelSource: `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/xnnpack/distiluse_base_multilingual_cased_v2_xnnpack_8da4w.pte`, - tokenizerSource: DISTILUSE_TOKENIZER, + modelSource: M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W_MODEL, + tokenizerSource: M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_TOKENIZER, }, }, coreml: { base: { modelName: 'distiluse-base-multilingual-cased-v2-coreml' as const, - modelSource: `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/coreml/distiluse_base_multilingual_cased_v2_coreml_fp32.pte`, - tokenizerSource: DISTILUSE_TOKENIZER, + modelSource: M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML_MODEL, + tokenizerSource: M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_TOKENIZER, }, }, }; diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index e18947deab..e90326367d 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -573,14 +573,18 @@ export const LFM2_VL_1_6B_QUANTIZED = LFM2_5_VL_1_6B_QUANTIZED; export const LFM2_VL_450M_QUANTIZED = LFM2_5_VL_450M_QUANTIZED; // Classification +export const EFFICIENTNET_V2_S_XNNPACK_FP32_MODEL = `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_fp32.pte`; +export const EFFICIENTNET_V2_S_XNNPACK_INT8_MODEL = `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_int8.pte`; +export const EFFICIENTNET_V2_S_COREML_FP32_MODEL = `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp32.pte`; +export const EFFICIENTNET_V2_S_COREML_FP16_MODEL = `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp16.pte`; const EFFICIENTNET_V2_S_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp32.pte` - : `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_fp32.pte`; + ? EFFICIENTNET_V2_S_COREML_FP32_MODEL + : EFFICIENTNET_V2_S_XNNPACK_FP32_MODEL; const EFFICIENTNET_V2_S_QUANTIZED_MODEL = Platform.OS === `ios` - ? `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/coreml/efficientnet_v2_s_coreml_fp16.pte` - : `${URL_PREFIX}-efficientnet-v2-s/${VERSION_TAG}/xnnpack/efficientnet_v2_s_xnnpack_int8.pte`; + ? EFFICIENTNET_V2_S_COREML_FP16_MODEL + : EFFICIENTNET_V2_S_XNNPACK_INT8_MODEL; /** * @category Models - Classification @@ -599,14 +603,18 @@ export const EFFICIENTNET_V2_S_QUANTIZED = { } as const; // Object detection +export const SSDLITE_320_MOBILENET_V3_LARGE_XNNPACK_FP32_MODEL = `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/xnnpack/ssdlite320_mobilenet_v3_large_xnnpack_fp32.pte`; +export const SSDLITE_320_MOBILENET_V3_LARGE_COREML_FP16_MODEL = `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/coreml/ssdlite320_mobilenet_v3_large_coreml_fp16.pte`; +export const RF_DETR_NANO_XNNPACK_FP32_MODEL = `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`; +export const RF_DETR_NANO_COREML_INT8_MODEL = `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`; const SSDLITE_320_MOBILENET_V3_LARGE_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/coreml/ssdlite320_mobilenet_v3_large_coreml_fp16.pte` - : `${URL_PREFIX}-ssdlite320-mobilenet-v3-large/${VERSION_TAG}/xnnpack/ssdlite320_mobilenet_v3_large_xnnpack_fp32.pte`; + ? SSDLITE_320_MOBILENET_V3_LARGE_COREML_FP16_MODEL + : SSDLITE_320_MOBILENET_V3_LARGE_XNNPACK_FP32_MODEL; const RF_DETR_NANO_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte` - : `${URL_PREFIX}-rfdetr-nano-detector/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`; + ? RF_DETR_NANO_COREML_INT8_MODEL + : RF_DETR_NANO_XNNPACK_FP32_MODEL; /** * @category Models - Object Detection @@ -683,38 +691,43 @@ export const YOLO26N_POSE = { } as const; // Style transfer +/** + * Builds the four `(backend, precision)` URLs for a single style-transfer + * style. `display` is the HF repo suffix (e.g. `rain-princess`) and `slug` is + * the .pte filename token (e.g. `rain_princess`); they differ for styles + * whose names contain spaces. + */ +export function styleTransferUrls< + const Display extends string, + const Slug extends string, +>(display: Display, slug: Slug) { + return { + xnnpackBase: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/xnnpack/style_transfer_${slug}_xnnpack_fp32.pte`, + xnnpackQuant: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/xnnpack/style_transfer_${slug}_xnnpack_int8.pte`, + coremlBase: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/coreml/style_transfer_${slug}_coreml_fp32.pte`, + coremlQuant: `${URL_PREFIX}-style-transfer-${display}/${VERSION_TAG}/coreml/style_transfer_${slug}_coreml_fp16.pte`, + }; +} +const STYLE_TRANSFER_CANDY_URLS = styleTransferUrls('candy', 'candy'); +const STYLE_TRANSFER_MOSAIC_URLS = styleTransferUrls('mosaic', 'mosaic'); +const STYLE_TRANSFER_RAIN_PRINCESS_URLS = styleTransferUrls('rain-princess', 'rain_princess'); +const STYLE_TRANSFER_UDNIE_URLS = styleTransferUrls('udnie', 'udnie'); const STYLE_TRANSFER_CANDY_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/coreml/style_transfer_candy_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/xnnpack/style_transfer_candy_xnnpack_fp32.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_CANDY_URLS.coremlBase : STYLE_TRANSFER_CANDY_URLS.xnnpackBase; const STYLE_TRANSFER_CANDY_QUANTIZED_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/coreml/style_transfer_candy_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-candy/${VERSION_TAG}/xnnpack/style_transfer_candy_xnnpack_int8.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_CANDY_URLS.coremlQuant : STYLE_TRANSFER_CANDY_URLS.xnnpackQuant; const STYLE_TRANSFER_MOSAIC_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/coreml/style_transfer_mosaic_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/xnnpack/style_transfer_mosaic_xnnpack_fp32.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_MOSAIC_URLS.coremlBase : STYLE_TRANSFER_MOSAIC_URLS.xnnpackBase; const STYLE_TRANSFER_MOSAIC_QUANTIZED_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/coreml/style_transfer_mosaic_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-mosaic/${VERSION_TAG}/xnnpack/style_transfer_mosaic_xnnpack_int8.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_MOSAIC_URLS.coremlQuant : STYLE_TRANSFER_MOSAIC_URLS.xnnpackQuant; const STYLE_TRANSFER_RAIN_PRINCESS_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/coreml/style_transfer_rain_princess_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/xnnpack/style_transfer_rain_princess_xnnpack_fp32.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_RAIN_PRINCESS_URLS.coremlBase : STYLE_TRANSFER_RAIN_PRINCESS_URLS.xnnpackBase; const STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/coreml/style_transfer_rain_princess_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-rain-princess/${VERSION_TAG}/xnnpack/style_transfer_rain_princess_xnnpack_int8.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_RAIN_PRINCESS_URLS.coremlQuant : STYLE_TRANSFER_RAIN_PRINCESS_URLS.xnnpackQuant; const STYLE_TRANSFER_UDNIE_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/coreml/style_transfer_udnie_coreml_fp32.pte` - : `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/xnnpack/style_transfer_udnie_xnnpack_fp32.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_UDNIE_URLS.coremlBase : STYLE_TRANSFER_UDNIE_URLS.xnnpackBase; const STYLE_TRANSFER_UDNIE_QUANTIZED_MODEL = - Platform.OS === `ios` - ? `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/coreml/style_transfer_udnie_coreml_fp16.pte` - : `${URL_PREFIX}-style-transfer-udnie/${VERSION_TAG}/xnnpack/style_transfer_udnie_xnnpack_int8.pte`; + Platform.OS === `ios` ? STYLE_TRANSFER_UDNIE_URLS.coremlQuant : STYLE_TRANSFER_UDNIE_URLS.xnnpackQuant; /** * @category Models - Style Transfer @@ -1019,14 +1032,14 @@ export const SELFIE_SEGMENTATION = { } as const; // FastSAM Instance Segmentation +export const FASTSAM_S_XNNPACK_FP32_MODEL = `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/xnnpack/fast_sam_s_xnnpack_fp32.pte`; +export const FASTSAM_S_COREML_FP16_MODEL = `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/coreml/fast_sam_s_coreml_fp16.pte`; +export const FASTSAM_X_XNNPACK_FP32_MODEL = `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/xnnpack/fast_sam_x_xnnpack_fp32.pte`; +export const FASTSAM_X_COREML_FP16_MODEL = `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/coreml/fast_sam_x_coreml_fp16.pte`; const FASTSAM_S_SEG_MODEL = - Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/coreml/fast_sam_s_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/s/xnnpack/fast_sam_s_xnnpack_fp32.pte`; + Platform.OS === 'ios' ? FASTSAM_S_COREML_FP16_MODEL : FASTSAM_S_XNNPACK_FP32_MODEL; const FASTSAM_X_SEG_MODEL = - Platform.OS === 'ios' - ? `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/coreml/fast_sam_x_coreml_fp16.pte` - : `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/xnnpack/fast_sam_x_xnnpack_fp32.pte`; + Platform.OS === 'ios' ? FASTSAM_X_COREML_FP16_MODEL : FASTSAM_X_XNNPACK_FP32_MODEL; /** * @category Models - Instance Segmentation @@ -1052,10 +1065,12 @@ const YOLO26S_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/s/xnnpack/yol const YOLO26M_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/m/xnnpack/yolo26_seg_m_xnnpack_fp32.pte`; const YOLO26L_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/l/xnnpack/yolo26_seg_l_xnnpack_fp32.pte`; const YOLO26X_SEG_MODEL = `${URL_PREFIX}-yolo26-seg/${VERSION_TAG}/x/xnnpack/yolo26_seg_x_xnnpack_fp32.pte`; +export const RF_DETR_NANO_SEG_XNNPACK_FP32_MODEL = `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`; +export const RF_DETR_NANO_SEG_COREML_INT8_MODEL = `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte`; const RF_DETR_NANO_SEG_MODEL = Platform.OS === 'ios' - ? `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/coreml/rfdetr_nano_coreml_int8.pte` - : `${URL_PREFIX}-rfdetr-nano-segmentation/${VERSION_TAG}/xnnpack/rfdetr_nano_xnnpack_fp32.pte`; + ? RF_DETR_NANO_SEG_COREML_INT8_MODEL + : RF_DETR_NANO_SEG_XNNPACK_FP32_MODEL; /** * @category Models - Instance Segmentation */ @@ -1133,9 +1148,9 @@ const MULTI_QA_MINILM_L6_COS_V1_MODEL = `${URL_PREFIX}-multi-qa-MiniLM-L6-cos-v1 const MULTI_QA_MINILM_L6_COS_V1_TOKENIZER = `${URL_PREFIX}-multi-qa-MiniLM-L6-cos-v1/${VERSION_TAG}/tokenizer.json`; const MULTI_QA_MPNET_BASE_DOT_V1_MODEL = `${URL_PREFIX}-multi-qa-mpnet-base-dot-v1/${VERSION_TAG}/xnnpack/multi_qa_mpnet_base_dot_v1_xnnpack_fp32.pte`; const MULTI_QA_MPNET_BASE_DOT_V1_TOKENIZER = `${URL_PREFIX}-multi-qa-mpnet-base-dot-v1/${VERSION_TAG}/tokenizer.json`; -const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/xnnpack/distiluse_base_multilingual_cased_v2_xnnpack_8da4w.pte`; -const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/coreml/distiluse_base_multilingual_cased_v2_coreml_fp32.pte`; -const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_TOKENIZER = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/tokenizer.json`; +export const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/xnnpack/distiluse_base_multilingual_cased_v2_xnnpack_8da4w.pte`; +export const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML_MODEL = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/coreml/distiluse_base_multilingual_cased_v2_coreml_fp32.pte`; +export const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_TOKENIZER = `${URL_PREFIX}-distiluse-base-multilingual-cased-v2/${VERSION_TAG}/tokenizer.json`; const PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED_MODEL = `${URL_PREFIX}-paraphrase-multilingual-MiniLM-L12-v2/${VERSION_TAG}/xnnpack/paraphrase_multilingual_minilm_l12_v2_xnnpack_8da4w.pte`; const PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_TOKENIZER = `${URL_PREFIX}-paraphrase-multilingual-MiniLM-L12-v2/${VERSION_TAG}/tokenizer.json`; const CLIP_VIT_BASE_PATCH32_TEXT_MODEL = `${URL_PREFIX}-clip-vit-base-patch32/${VERSION_TAG}/xnnpack/clip_vit_base_patch32_text_xnnpack_fp32.pte`; From eff6ade137278b904940016c50a4ff0723de67f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Mon, 18 May 2026 09:38:31 +0200 Subject: [PATCH 11/16] chore(constants): satisfy lint (jsdoc @param + prettier multi-line ternaries) --- .../src/constants/modelUrls.ts | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index e90326367d..fde55814bc 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -693,9 +693,11 @@ export const YOLO26N_POSE = { // Style transfer /** * Builds the four `(backend, precision)` URLs for a single style-transfer - * style. `display` is the HF repo suffix (e.g. `rain-princess`) and `slug` is - * the .pte filename token (e.g. `rain_princess`); they differ for styles - * whose names contain spaces. + * style. + * + * @param display - HF repo suffix (e.g. `rain-princess`). + * @param slug - .pte filename token (e.g. `rain_princess`). Differs from + * `display` for styles whose names contain spaces. */ export function styleTransferUrls< const Display extends string, @@ -710,24 +712,43 @@ export function styleTransferUrls< } const STYLE_TRANSFER_CANDY_URLS = styleTransferUrls('candy', 'candy'); const STYLE_TRANSFER_MOSAIC_URLS = styleTransferUrls('mosaic', 'mosaic'); -const STYLE_TRANSFER_RAIN_PRINCESS_URLS = styleTransferUrls('rain-princess', 'rain_princess'); +const STYLE_TRANSFER_RAIN_PRINCESS_URLS = styleTransferUrls( + 'rain-princess', + 'rain_princess' +); const STYLE_TRANSFER_UDNIE_URLS = styleTransferUrls('udnie', 'udnie'); const STYLE_TRANSFER_CANDY_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_CANDY_URLS.coremlBase : STYLE_TRANSFER_CANDY_URLS.xnnpackBase; + Platform.OS === `ios` + ? STYLE_TRANSFER_CANDY_URLS.coremlBase + : STYLE_TRANSFER_CANDY_URLS.xnnpackBase; const STYLE_TRANSFER_CANDY_QUANTIZED_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_CANDY_URLS.coremlQuant : STYLE_TRANSFER_CANDY_URLS.xnnpackQuant; + Platform.OS === `ios` + ? STYLE_TRANSFER_CANDY_URLS.coremlQuant + : STYLE_TRANSFER_CANDY_URLS.xnnpackQuant; const STYLE_TRANSFER_MOSAIC_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_MOSAIC_URLS.coremlBase : STYLE_TRANSFER_MOSAIC_URLS.xnnpackBase; + Platform.OS === `ios` + ? STYLE_TRANSFER_MOSAIC_URLS.coremlBase + : STYLE_TRANSFER_MOSAIC_URLS.xnnpackBase; const STYLE_TRANSFER_MOSAIC_QUANTIZED_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_MOSAIC_URLS.coremlQuant : STYLE_TRANSFER_MOSAIC_URLS.xnnpackQuant; + Platform.OS === `ios` + ? STYLE_TRANSFER_MOSAIC_URLS.coremlQuant + : STYLE_TRANSFER_MOSAIC_URLS.xnnpackQuant; const STYLE_TRANSFER_RAIN_PRINCESS_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_RAIN_PRINCESS_URLS.coremlBase : STYLE_TRANSFER_RAIN_PRINCESS_URLS.xnnpackBase; + Platform.OS === `ios` + ? STYLE_TRANSFER_RAIN_PRINCESS_URLS.coremlBase + : STYLE_TRANSFER_RAIN_PRINCESS_URLS.xnnpackBase; const STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_RAIN_PRINCESS_URLS.coremlQuant : STYLE_TRANSFER_RAIN_PRINCESS_URLS.xnnpackQuant; + Platform.OS === `ios` + ? STYLE_TRANSFER_RAIN_PRINCESS_URLS.coremlQuant + : STYLE_TRANSFER_RAIN_PRINCESS_URLS.xnnpackQuant; const STYLE_TRANSFER_UDNIE_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_UDNIE_URLS.coremlBase : STYLE_TRANSFER_UDNIE_URLS.xnnpackBase; + Platform.OS === `ios` + ? STYLE_TRANSFER_UDNIE_URLS.coremlBase + : STYLE_TRANSFER_UDNIE_URLS.xnnpackBase; const STYLE_TRANSFER_UDNIE_QUANTIZED_MODEL = - Platform.OS === `ios` ? STYLE_TRANSFER_UDNIE_URLS.coremlQuant : STYLE_TRANSFER_UDNIE_URLS.xnnpackQuant; + Platform.OS === `ios` + ? STYLE_TRANSFER_UDNIE_URLS.coremlQuant + : STYLE_TRANSFER_UDNIE_URLS.xnnpackQuant; /** * @category Models - Style Transfer @@ -1037,9 +1058,13 @@ export const FASTSAM_S_COREML_FP16_MODEL = `${URL_PREFIX}-fast-sam/${VERSION_TAG export const FASTSAM_X_XNNPACK_FP32_MODEL = `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/xnnpack/fast_sam_x_xnnpack_fp32.pte`; export const FASTSAM_X_COREML_FP16_MODEL = `${URL_PREFIX}-fast-sam/${VERSION_TAG}/x/coreml/fast_sam_x_coreml_fp16.pte`; const FASTSAM_S_SEG_MODEL = - Platform.OS === 'ios' ? FASTSAM_S_COREML_FP16_MODEL : FASTSAM_S_XNNPACK_FP32_MODEL; + Platform.OS === 'ios' + ? FASTSAM_S_COREML_FP16_MODEL + : FASTSAM_S_XNNPACK_FP32_MODEL; const FASTSAM_X_SEG_MODEL = - Platform.OS === 'ios' ? FASTSAM_X_COREML_FP16_MODEL : FASTSAM_X_XNNPACK_FP32_MODEL; + Platform.OS === 'ios' + ? FASTSAM_X_COREML_FP16_MODEL + : FASTSAM_X_XNNPACK_FP32_MODEL; /** * @category Models - Instance Segmentation From b7be4565eb4c0b380f3d33df045bf575f0bf7fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Mon, 18 May 2026 17:48:09 +0200 Subject: [PATCH 12/16] refactor(registry)!: function-only lowercase \`models\`; add multimodal/tts/ocr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopts Bartek's feedback on #1148 — the accessor is no longer dual-shaped (value AND function). Each leaf is a pure function: call it (optionally with \`{ quant, backend }\`) to get the resolved config. This eliminates the \`useState\` lazy-init footgun and \`useMemo\`/\`useCallback\` dep hazards, so pickers fall back to plain \`===\` reference equality (drops the \`sameValue\` workaround across four \`ModelPicker.tsx\` files). Renames: - \`MODEL_REGISTRY\` → \`models\` (lowercase top-level) - group keys lowercased: \`LLM\` → \`llm\`, etc. - per Kuba: \`vlm\` → \`multimodal\` (anticipates audio-capable LMs like Gemma 4) Adds: - \`models.text_to_speech\` group: \`kokoro_small\`, \`kokoro_medium\`, plus voices as plain configs under \`voices\` (no quant/backend axis). - \`models.ocr({ language })\` parameterized accessor — covers all ISO language tokens via a runtime map built from the existing \`OCR_\` exports. Example apps (22 files, ~150 substitutions) migrated by script. bare-rn demo swapped from \`llama3_2_1b\` to \`lfm2_5_1_2b_instruct\` per Kuba's note. Docs rewritten with the new syntax + TTS + OCR sections. Relaxes the project's \`camelcase\` rule with \`properties: 'never'\` so the lowercase snake_case keys in \`models\` (which mirror the \`.pte\` filename convention) pass without per-file disables. Variable and function names still require camelCase. --- .eslintrc.js | 6 +- apps/bare-rn/App.tsx | 8 +- .../app/classification/index.tsx | 8 +- .../app/instance_segmentation/index.tsx | 20 +- .../app/object_detection/index.tsx | 18 +- .../app/segment_anything/index.tsx | 12 +- .../app/semantic_segmentation/index.tsx | 18 +- .../app/style_transfer/index.tsx | 12 +- .../app/text_to_image/index.tsx | 8 +- .../components/ModelPicker.tsx | 15 +- .../tasks/ClassificationTask.tsx | 4 +- .../tasks/InstanceSegmentationTask.tsx | 10 +- .../tasks/ObjectDetectionTask.tsx | 8 +- .../vision_camera/tasks/SegmentationTask.tsx | 19 +- .../vision_camera/tasks/StyleTransferTask.tsx | 6 +- apps/llm/app/llm/index.tsx | 4 +- apps/llm/app/llm_structured_output/index.tsx | 4 +- apps/llm/app/llm_tool_calling/index.tsx | 8 +- apps/llm/app/multimodal_llm/index.tsx | 4 +- apps/llm/app/voice_chat/index.tsx | 20 +- apps/llm/components/ModelPicker.tsx | 15 +- apps/llm/components/llmModels.ts | 78 ++--- apps/speech/components/ModelPicker.tsx | 15 +- apps/speech/screens/SpeechToTextScreen.tsx | 12 +- .../app/clip-embeddings/index.tsx | 10 +- .../app/text-embeddings/index.tsx | 26 +- .../components/ModelPicker.tsx | 15 +- docs/docs/05-utilities/model-registry.md | 125 ++++---- .../src/constants/modelRegistry.ts | 295 ++++++++++-------- 29 files changed, 405 insertions(+), 398 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 35d2da64cc..b09ff37d23 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -63,7 +63,11 @@ module.exports = { customWordListFile: path.resolve(__dirname, '.cspell-wordlist.txt'), }, ], - 'camelcase': 'error', + // `properties: 'never'` lets the lowercase snake_case keys in `models` + // (e.g. `models.text_to_speech.kokoro_small`, mirroring the underlying + // `.pte` filenames) pass while still requiring camelCase for variable + // and function declarations. + 'camelcase': ['error', { properties: 'never' }], 'jsdoc/require-jsdoc': 'off', 'jsdoc/require-param': ['error', { checkDestructured: false }], 'jsdoc/check-param-names': ['error', { checkDestructured: false }], diff --git a/apps/bare-rn/App.tsx b/apps/bare-rn/App.tsx index d6575bee6a..cb6af0aa33 100644 --- a/apps/bare-rn/App.tsx +++ b/apps/bare-rn/App.tsx @@ -13,11 +13,7 @@ import { TouchableWithoutFeedback, View, } from 'react-native'; -import { - MODEL_REGISTRY, - initExecutorch, - useLLM, -} from 'react-native-executorch'; +import { models, initExecutorch, useLLM } from 'react-native-executorch'; import { BareResourceFetcher } from 'react-native-executorch-bare-resource-fetcher'; import { setConfig } from '@kesha-antonov/react-native-background-downloader'; import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'; @@ -145,7 +141,7 @@ function App() { const scrollViewRef = useRef(null); const llm = useLLM({ - model: MODEL_REGISTRY.LLM.LLAMA3_2_1B, + model: models.llm.lfm2_5_1_2b_instruct(), }); // Alternatively, to use a custom local model, uncomment below: // const llm = useLLM({ model: { diff --git a/apps/computer-vision/app/classification/index.tsx b/apps/computer-vision/app/classification/index.tsx index b1f4fe5d77..e2e9e3985e 100644 --- a/apps/computer-vision/app/classification/index.tsx +++ b/apps/computer-vision/app/classification/index.tsx @@ -1,7 +1,7 @@ import Spinner from '../../components/Spinner'; import { getImage } from '../../utils'; import { - MODEL_REGISTRY, + models, useClassification, ClassificationModelSources, } from 'react-native-executorch'; @@ -10,11 +10,11 @@ import { ModelPicker, ModelOption } from '../../components/ModelPicker'; const MODELS: ModelOption[] = [ { label: 'EfficientNet V2 S Quantized', - value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S, + value: models.classification.efficientnet_v2_s(), }, { label: 'EfficientNet V2 S', - value: MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: false }), + value: models.classification.efficientnet_v2_s({ quant: false }), }, ]; import { View, StyleSheet, Image, Text, ScrollView } from 'react-native'; @@ -28,7 +28,7 @@ import ErrorBanner from '../../components/ErrorBanner'; export default function ClassificationScreen() { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S + models.classification.efficientnet_v2_s() ); const [results, setResults] = useState<{ label: string; score: number }[]>( [] diff --git a/apps/computer-vision/app/instance_segmentation/index.tsx b/apps/computer-vision/app/instance_segmentation/index.tsx index 6a7a98baf0..62cfd249df 100644 --- a/apps/computer-vision/app/instance_segmentation/index.tsx +++ b/apps/computer-vision/app/instance_segmentation/index.tsx @@ -3,7 +3,7 @@ import { BottomBar } from '../../components/BottomBar'; import { getImage } from '../../utils'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { - MODEL_REGISTRY, + models, useInstanceSegmentation, InstanceSegmentationModelSources, } from 'react-native-executorch'; @@ -24,23 +24,23 @@ import ImageWithMasks, { import { StatsBar } from '../../components/StatsBar'; const MODELS: ModelOption[] = [ - { label: 'Yolo26N', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26N_SEG }, - { label: 'Yolo26S', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26S_SEG }, - { label: 'Yolo26M', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26M_SEG }, - { label: 'Yolo26L', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26L_SEG }, - { label: 'Yolo26X', value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26X_SEG }, + { label: 'Yolo26N', value: models.instance_segmentation.yolo26n_seg() }, + { label: 'Yolo26S', value: models.instance_segmentation.yolo26s_seg() }, + { label: 'Yolo26M', value: models.instance_segmentation.yolo26m_seg() }, + { label: 'Yolo26L', value: models.instance_segmentation.yolo26l_seg() }, + { label: 'Yolo26X', value: models.instance_segmentation.yolo26x_seg() }, { label: 'RF-DeTR Nano', - value: MODEL_REGISTRY.INSTANCE_SEGMENTATION.RF_DETR_NANO_SEG, + value: models.instance_segmentation.rf_detr_nano_seg(), }, - { label: 'FastSAM-S', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_S }, - { label: 'FastSAM-X', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_X }, + { label: 'FastSAM-S', value: models.object_detection.fastsam_s() }, + { label: 'FastSAM-X', value: models.object_detection.fastsam_x() }, ]; export default function InstanceSegmentationScreen() { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.INSTANCE_SEGMENTATION.YOLO26N_SEG + models.instance_segmentation.yolo26n_seg() ); const [inferenceTime, setInferenceTime] = useState(null); diff --git a/apps/computer-vision/app/object_detection/index.tsx b/apps/computer-vision/app/object_detection/index.tsx index a369f1d9aa..a21936c574 100644 --- a/apps/computer-vision/app/object_detection/index.tsx +++ b/apps/computer-vision/app/object_detection/index.tsx @@ -3,7 +3,7 @@ import { BottomBar } from '../../components/BottomBar'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { getImage } from '../../utils'; import { - MODEL_REGISTRY, + models, Detection, useObjectDetection, ObjectDetectionModelSources, @@ -18,17 +18,17 @@ import { StatsBar } from '../../components/StatsBar'; const MODELS: ModelOption[] = [ { label: 'RF-DeTR Nano', - value: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO, + value: models.object_detection.rf_detr_nano(), }, { label: 'SSDLite MobileNet', - value: MODEL_REGISTRY.OBJECT_DETECTION.SSDLITE_320_MOBILENET_V3_LARGE, + value: models.object_detection.ssdlite_320_mobilenet_v3_large(), }, - { label: 'YOLO26N', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26N }, - { label: 'YOLO26S', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26S }, - { label: 'YOLO26M', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26M }, - { label: 'YOLO26L', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26L }, - { label: 'YOLO26X', value: MODEL_REGISTRY.OBJECT_DETECTION.YOLO26X }, + { label: 'YOLO26N', value: models.object_detection.yolo26n() }, + { label: 'YOLO26S', value: models.object_detection.yolo26s() }, + { label: 'YOLO26M', value: models.object_detection.yolo26m() }, + { label: 'YOLO26L', value: models.object_detection.yolo26l() }, + { label: 'YOLO26X', value: models.object_detection.yolo26x() }, ]; import ErrorBanner from '../../components/ErrorBanner'; @@ -42,7 +42,7 @@ export default function ObjectDetectionScreen() { }>(); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO + models.object_detection.rf_detr_nano() ); const [inferenceTime, setInferenceTime] = useState(null); diff --git a/apps/computer-vision/app/segment_anything/index.tsx b/apps/computer-vision/app/segment_anything/index.tsx index 236951c3c4..f8bf50fd3a 100644 --- a/apps/computer-vision/app/segment_anything/index.tsx +++ b/apps/computer-vision/app/segment_anything/index.tsx @@ -21,7 +21,7 @@ import { AlphaType, } from '@shopify/react-native-skia'; import { - MODEL_REGISTRY, + models, useInstanceSegmentation, useImageEmbeddings, useTextEmbeddings, @@ -49,8 +49,8 @@ import ColorPalette from '../../colors'; type PromptMode = 'point' | 'box' | 'text'; const MODELS: ModelOption[] = [ - { label: 'FastSAM-S', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_S }, - { label: 'FastSAM-X', value: MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_X }, + { label: 'FastSAM-S', value: models.object_detection.fastsam_s() }, + { label: 'FastSAM-X', value: models.object_detection.fastsam_x() }, ]; export default function SegmentAnythingScreen() { @@ -58,7 +58,7 @@ export default function SegmentAnythingScreen() { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.OBJECT_DETECTION.FASTSAM_S + models.object_detection.fastsam_s() ); const [mode, setMode] = useState('point'); const [inferenceTime, setInferenceTime] = useState(null); @@ -77,10 +77,10 @@ export default function SegmentAnythingScreen() { useInstanceSegmentation({ model: selectedModel }); const clipImage = useImageEmbeddings({ - model: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE, + model: models.image_embedding.clip_vit_base_patch32_image(), }); const clipText = useTextEmbeddings({ - model: MODEL_REGISTRY.TEXT_EMBEDDING.CLIP_VIT_BASE_PATCH32_TEXT, + model: models.text_embedding.clip_vit_base_patch32_text(), }); const skiaSource = useImage(imageUri || null); diff --git a/apps/computer-vision/app/semantic_segmentation/index.tsx b/apps/computer-vision/app/semantic_segmentation/index.tsx index 04d8f3b750..5f969d83e2 100644 --- a/apps/computer-vision/app/semantic_segmentation/index.tsx +++ b/apps/computer-vision/app/semantic_segmentation/index.tsx @@ -3,7 +3,7 @@ import { BottomBar } from '../../components/BottomBar'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { getImage } from '../../utils'; import { - MODEL_REGISTRY, + models, useSemanticSegmentation, SemanticSegmentationModelSources, } from 'react-native-executorch'; @@ -49,31 +49,31 @@ const numberToColor: number[][] = [ const MODELS: ModelOption[] = [ { label: 'DeepLab MobileNet', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE, + value: models.semantic_segmentation.deeplab_v3_mobilenet_v3_large(), }, { label: 'DeepLab ResNet50', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET50, + value: models.semantic_segmentation.deeplab_v3_resnet50(), }, { label: 'DeepLab ResNet101', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_RESNET101, + value: models.semantic_segmentation.deeplab_v3_resnet101(), }, { label: 'LRASPP MobileNet', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.LRASPP_MOBILENET_V3_LARGE, + value: models.semantic_segmentation.lraspp_mobilenet_v3_large(), }, { label: 'FCN ResNet50', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET50, + value: models.semantic_segmentation.fcn_resnet50(), }, { label: 'FCN ResNet101', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.FCN_RESNET101, + value: models.semantic_segmentation.fcn_resnet101(), }, { label: 'Selfie Segmentation', - value: MODEL_REGISTRY.SEMANTIC_SEGMENTATION.SELFIE_SEGMENTATION, + value: models.semantic_segmentation.selfie_segmentation(), }, ]; @@ -81,7 +81,7 @@ export default function SemanticSegmentationScreen() { const { setGlobalGenerating } = useContext(GeneratingContext); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.SEMANTIC_SEGMENTATION.DEEPLAB_V3_MOBILENET_V3_LARGE + models.semantic_segmentation.deeplab_v3_mobilenet_v3_large() ); const { diff --git a/apps/computer-vision/app/style_transfer/index.tsx b/apps/computer-vision/app/style_transfer/index.tsx index ed1367202c..4d777a3b1f 100644 --- a/apps/computer-vision/app/style_transfer/index.tsx +++ b/apps/computer-vision/app/style_transfer/index.tsx @@ -3,7 +3,7 @@ import { BottomBar } from '../../components/BottomBar'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; import { getImage } from '../../utils'; import { - MODEL_REGISTRY, + models, useStyleTransfer, StyleTransferModelName, ResourceSource, @@ -22,19 +22,19 @@ type StyleTransferModelSources = { }; const MODELS: ModelOption[] = [ - { label: 'Candy', value: MODEL_REGISTRY.STYLE_TRANSFER.CANDY }, - { label: 'Mosaic', value: MODEL_REGISTRY.STYLE_TRANSFER.MOSAIC }, + { label: 'Candy', value: models.style_transfer.candy() }, + { label: 'Mosaic', value: models.style_transfer.mosaic() }, { label: 'Rain Princess', - value: MODEL_REGISTRY.STYLE_TRANSFER.RAIN_PRINCESS, + value: models.style_transfer.rain_princess(), }, - { label: 'Udnie', value: MODEL_REGISTRY.STYLE_TRANSFER.UDNIE }, + { label: 'Udnie', value: models.style_transfer.udnie() }, ]; import ErrorBanner from '../../components/ErrorBanner'; export default function StyleTransferScreen() { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.STYLE_TRANSFER.CANDY + models.style_transfer.candy() ); const model = useStyleTransfer({ model: selectedModel }); diff --git a/apps/computer-vision/app/text_to_image/index.tsx b/apps/computer-vision/app/text_to_image/index.tsx index cfc63b8bca..f2a6fd5a66 100644 --- a/apps/computer-vision/app/text_to_image/index.tsx +++ b/apps/computer-vision/app/text_to_image/index.tsx @@ -14,7 +14,7 @@ import React, { useContext, useEffect, useState } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import Spinner from '../../components/Spinner'; import { - MODEL_REGISTRY, + models, useTextToImage, TextToImageProps, } from 'react-native-executorch'; @@ -31,11 +31,11 @@ type TextToImageModelSources = TextToImageProps['model']; const MODELS: ModelOption[] = [ { label: 'BK-SDM 256', - value: MODEL_REGISTRY.IMAGE_GENERATION.BK_SDM_TINY_VPRED_256, + value: models.image_generation.bk_sdm_tiny_vpred_256(), }, { label: 'BK-SDM 512', - value: MODEL_REGISTRY.IMAGE_GENERATION.BK_SDM_TINY_VPRED_512, + value: models.image_generation.bk_sdm_tiny_vpred_512(), }, ]; @@ -47,7 +47,7 @@ export default function TextToImageScreen() { const [input, setInput] = useState(''); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.IMAGE_GENERATION.BK_SDM_TINY_VPRED_256 + models.image_generation.bk_sdm_tiny_vpred_256() ); const [generationTime, setGenerationTime] = useState(null); diff --git a/apps/computer-vision/components/ModelPicker.tsx b/apps/computer-vision/components/ModelPicker.tsx index 483532f29a..94a848596e 100644 --- a/apps/computer-vision/components/ModelPicker.tsx +++ b/apps/computer-vision/components/ModelPicker.tsx @@ -24,17 +24,6 @@ type Props = { const DROPDOWN_MAX_HEIGHT = 200; -// MODEL_REGISTRY accessors are functions, so passing them to useState makes -// React auto-invoke them as lazy initializers — state becomes the underlying -// config object, breaking reference equality against the accessor in MODELS. -// Match by modelName when both sides expose one, otherwise fall back to ===. -function sameValue(a: T, b: T): boolean { - const am = (a as { modelName?: unknown })?.modelName; - const bm = (b as { modelName?: unknown })?.modelName; - if (typeof am === 'string' && typeof bm === 'string') return am === bm; - return a === b; -} - export function ModelPicker({ models, selectedModel, @@ -47,7 +36,7 @@ export function ModelPicker({ const [expandUp, setExpandUp] = useState(false); const [dropdownTop, setDropdownTop] = useState(0); const triggerRef = useRef>(null); - const selected = models.find((m) => sameValue(m.value, selectedModel)); + const selected = models.find((m) => m.value === selectedModel); useEffect(() => { if (disabled) setOpen(false); @@ -123,7 +112,7 @@ export function ModelPicker({ showsVerticalScrollIndicator={true} > {models.map((item) => { - const isSelected = sameValue(item.value, selectedModel); + const isSelected = item.value === selectedModel; return ( ( - MODEL_REGISTRY.LLM.LLAMA3_2_1B + models.llm.llama3_2_1b() ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/llm_structured_output/index.tsx b/apps/llm/app/llm_structured_output/index.tsx index b6eeadeb62..8150da4d6c 100644 --- a/apps/llm/app/llm_structured_output/index.tsx +++ b/apps/llm/app/llm_structured_output/index.tsx @@ -24,7 +24,7 @@ import { useLLMStats } from '../../hooks/useLLMStats'; import { StatsBar } from '../../components/StatsBar'; import ErrorBanner from '../../components/ErrorBanner'; import { - MODEL_REGISTRY, + models, useLLM, fixAndValidateStructuredOutput, getStructuredOutputPrompt, @@ -84,7 +84,7 @@ function LLMScreen() { const [isTextInputFocused, setIsTextInputFocused] = useState(false); const [userInput, setUserInput] = useState(''); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.LLM.QWEN3_1_7B + models.llm.qwen3_1_7b() ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/llm_tool_calling/index.tsx b/apps/llm/app/llm_tool_calling/index.tsx index 19b2ece57b..f059d59793 100644 --- a/apps/llm/app/llm_tool_calling/index.tsx +++ b/apps/llm/app/llm_tool_calling/index.tsx @@ -17,11 +17,7 @@ import SWMIcon from '../../assets/icons/swm_icon.svg'; import SendIcon from '../../assets/icons/send_icon.svg'; import Spinner from '../../components/Spinner'; import ErrorBanner from '../../components/ErrorBanner'; -import { - MODEL_REGISTRY, - useLLM, - DEFAULT_SYSTEM_PROMPT, -} from 'react-native-executorch'; +import { models, useLLM, DEFAULT_SYSTEM_PROMPT } from 'react-native-executorch'; import { ModelPicker } from '../../components/ModelPicker'; import { LLM_MODELS, LLMModelSources } from '../../components/llmModels'; import PauseIcon from '../../assets/icons/pause_icon.svg'; @@ -55,7 +51,7 @@ function LLMToolCallingScreen() { const [hasCalendarPermission, setHasCalendarPermission] = useState(true); const [hasBrightnessPermission, setHasBrightnessPermission] = useState(true); const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.LLM.HAMMER2_1_1_5B + models.llm.hammer2_1_1_5b() ); const textInputRef = useRef(null); const { setGlobalGenerating } = useContext(GeneratingContext); diff --git a/apps/llm/app/multimodal_llm/index.tsx b/apps/llm/app/multimodal_llm/index.tsx index 22dee14419..408798e967 100644 --- a/apps/llm/app/multimodal_llm/index.tsx +++ b/apps/llm/app/multimodal_llm/index.tsx @@ -14,7 +14,7 @@ import { import { launchImageLibrary } from 'react-native-image-picker'; import { useIsFocused } from '@react-navigation/native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { MODEL_REGISTRY, useLLM } from 'react-native-executorch'; +import { models, useLLM } from 'react-native-executorch'; import SendIcon from '../../assets/icons/send_icon.svg'; import PauseIcon from '../../assets/icons/pause_icon.svg'; import ColorPalette from '../../colors'; @@ -50,7 +50,7 @@ function MultimodalLLMScreen() { const [error, setError] = useState(null); const vlm = useLLM({ - model: MODEL_REGISTRY.VLM.LFM2_5_VL_1_6B, + model: models.multimodal.lfm2_5_vl_1_6b(), }); const tokenCount = vlm.isReady ? vlm.getGeneratedTokenCount() : 0; const { stats, onMessageSend } = useLLMStats( diff --git a/apps/llm/app/voice_chat/index.tsx b/apps/llm/app/voice_chat/index.tsx index a485aa33d5..23a18eaec7 100644 --- a/apps/llm/app/voice_chat/index.tsx +++ b/apps/llm/app/voice_chat/index.tsx @@ -13,7 +13,7 @@ import SWMIcon from '../../assets/icons/swm_icon.svg'; import Spinner from '../../components/Spinner'; import ErrorBanner from '../../components/ErrorBanner'; import { - MODEL_REGISTRY, + models, useSpeechToText, useLLM, LLMProps, @@ -35,27 +35,27 @@ type LLMModelSources = LLMProps['model']; type STTModelSources = SpeechToTextProps['model']; const LLM_MODELS: ModelOption[] = [ - { label: 'Qwen3 0.6B', value: MODEL_REGISTRY.LLM.QWEN3_0_6B }, - { label: 'Qwen3 1.7B', value: MODEL_REGISTRY.LLM.QWEN3_1_7B }, - { label: 'Llama 1B', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B }, + { label: 'Qwen3 0.6B', value: models.llm.qwen3_0_6b() }, + { label: 'Qwen3 1.7B', value: models.llm.qwen3_1_7b() }, + { label: 'Llama 1B', value: models.llm.llama3_2_1b() }, ]; const STT_MODELS: ModelOption[] = [ { label: 'Whisper Tiny', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }), + value: models.speech_to_text.whisper_tiny_en({ quant: false }), }, { label: 'Whisper Tiny Q', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, + value: models.speech_to_text.whisper_tiny_en(), }, { label: 'Whisper Base', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_BASE_EN, + value: models.speech_to_text.whisper_base_en(), }, { label: 'Whisper Small', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_SMALL_EN, + value: models.speech_to_text.whisper_small_en(), }, ]; @@ -70,10 +70,10 @@ function VoiceChatScreen() { const [isRecording, setIsRecording] = useState(false); const [liveTranscription, setLiveTranscription] = useState(''); const [selectedLLM, setSelectedLLM] = useState( - MODEL_REGISTRY.LLM.QWEN3_0_6B + models.llm.qwen3_0_6b() ); const [selectedSTT, setSelectedSTT] = useState( - MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }) + models.speech_to_text.whisper_tiny_en({ quant: false }) ); const [error, setError] = useState(null); diff --git a/apps/llm/components/ModelPicker.tsx b/apps/llm/components/ModelPicker.tsx index 483532f29a..94a848596e 100644 --- a/apps/llm/components/ModelPicker.tsx +++ b/apps/llm/components/ModelPicker.tsx @@ -24,17 +24,6 @@ type Props = { const DROPDOWN_MAX_HEIGHT = 200; -// MODEL_REGISTRY accessors are functions, so passing them to useState makes -// React auto-invoke them as lazy initializers — state becomes the underlying -// config object, breaking reference equality against the accessor in MODELS. -// Match by modelName when both sides expose one, otherwise fall back to ===. -function sameValue(a: T, b: T): boolean { - const am = (a as { modelName?: unknown })?.modelName; - const bm = (b as { modelName?: unknown })?.modelName; - if (typeof am === 'string' && typeof bm === 'string') return am === bm; - return a === b; -} - export function ModelPicker({ models, selectedModel, @@ -47,7 +36,7 @@ export function ModelPicker({ const [expandUp, setExpandUp] = useState(false); const [dropdownTop, setDropdownTop] = useState(0); const triggerRef = useRef>(null); - const selected = models.find((m) => sameValue(m.value, selectedModel)); + const selected = models.find((m) => m.value === selectedModel); useEffect(() => { if (disabled) setOpen(false); @@ -123,7 +112,7 @@ export function ModelPicker({ showsVerticalScrollIndicator={true} > {models.map((item) => { - const isSelected = sameValue(item.value, selectedModel); + const isSelected = item.value === selectedModel; return ( [] = [ // Llama 3.2 { label: 'Llama 3.2 1B', - value: MODEL_REGISTRY.LLM.LLAMA3_2_1B({ quant: false }), + value: models.llm.llama3_2_1b({ quant: false }), }, { label: 'Llama 3.2 1B QLoRA', value: LLAMA3_2_1B_QLORA }, - { label: 'Llama 3.2 1B SpinQuant', value: MODEL_REGISTRY.LLM.LLAMA3_2_1B }, + { label: 'Llama 3.2 1B SpinQuant', value: models.llm.llama3_2_1b() }, { label: 'Llama 3.2 3B', - value: MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false }), + value: models.llm.llama3_2_3b({ quant: false }), }, { label: 'Llama 3.2 3B QLoRA', value: LLAMA3_2_3B_QLORA }, - { label: 'Llama 3.2 3B SpinQuant', value: MODEL_REGISTRY.LLM.LLAMA3_2_3B }, + { label: 'Llama 3.2 3B SpinQuant', value: models.llm.llama3_2_3b() }, // Qwen3 { label: 'Qwen3 0.6B', - value: MODEL_REGISTRY.LLM.QWEN3_0_6B({ quant: false }), + value: models.llm.qwen3_0_6b({ quant: false }), }, - { label: 'Qwen3 0.6B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_0_6B }, + { label: 'Qwen3 0.6B Quantized', value: models.llm.qwen3_0_6b() }, { label: 'Qwen3 1.7B', - value: MODEL_REGISTRY.LLM.QWEN3_1_7B({ quant: false }), + value: models.llm.qwen3_1_7b({ quant: false }), }, - { label: 'Qwen3 1.7B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_1_7B }, - { label: 'Qwen3 4B', value: MODEL_REGISTRY.LLM.QWEN3_4B({ quant: false }) }, - { label: 'Qwen3 4B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_4B }, + { label: 'Qwen3 1.7B Quantized', value: models.llm.qwen3_1_7b() }, + { label: 'Qwen3 4B', value: models.llm.qwen3_4b({ quant: false }) }, + { label: 'Qwen3 4B Quantized', value: models.llm.qwen3_4b() }, // Hammer 2.1 { label: 'Hammer 2.1 0.5B', - value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B({ quant: false }), + value: models.llm.hammer2_1_0_5b({ quant: false }), }, { label: 'Hammer 2.1 0.5B Quantized', - value: MODEL_REGISTRY.LLM.HAMMER2_1_0_5B, + value: models.llm.hammer2_1_0_5b(), }, { label: 'Hammer 2.1 1.5B', - value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B({ quant: false }), + value: models.llm.hammer2_1_1_5b({ quant: false }), }, { label: 'Hammer 2.1 1.5B Quantized', - value: MODEL_REGISTRY.LLM.HAMMER2_1_1_5B, + value: models.llm.hammer2_1_1_5b(), }, { label: 'Hammer 2.1 3B', - value: MODEL_REGISTRY.LLM.HAMMER2_1_3B({ quant: false }), + value: models.llm.hammer2_1_3b({ quant: false }), }, { label: 'Hammer 2.1 3B Quantized', - value: MODEL_REGISTRY.LLM.HAMMER2_1_3B, + value: models.llm.hammer2_1_3b(), }, // SmolLM2 { label: 'SmolLM2 135M', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M({ quant: false }), + value: models.llm.smollm2_1_135m({ quant: false }), }, { label: 'SmolLM2 135M Quantized', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_135M, + value: models.llm.smollm2_1_135m(), }, { label: 'SmolLM2 360M', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M({ quant: false }), + value: models.llm.smollm2_1_360m({ quant: false }), }, { label: 'SmolLM2 360M Quantized', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_360M, + value: models.llm.smollm2_1_360m(), }, { label: 'SmolLM2 1.7B', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B({ quant: false }), + value: models.llm.smollm2_1_1_7b({ quant: false }), }, { label: 'SmolLM2 1.7B Quantized', - value: MODEL_REGISTRY.LLM.SMOLLM2_1_1_7B, + value: models.llm.smollm2_1_1_7b(), }, // Qwen2.5 { label: 'Qwen2.5 0.5B', - value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B({ quant: false }), + value: models.llm.qwen2_5_0_5b({ quant: false }), }, { label: 'Qwen2.5 0.5B Quantized', - value: MODEL_REGISTRY.LLM.QWEN2_5_0_5B, + value: models.llm.qwen2_5_0_5b(), }, { label: 'Qwen2.5 1.5B', - value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B({ quant: false }), + value: models.llm.qwen2_5_1_5b({ quant: false }), }, { label: 'Qwen2.5 1.5B Quantized', - value: MODEL_REGISTRY.LLM.QWEN2_5_1_5B, + value: models.llm.qwen2_5_1_5b(), }, { label: 'Qwen2.5 3B', - value: MODEL_REGISTRY.LLM.QWEN2_5_3B({ quant: false }), + value: models.llm.qwen2_5_3b({ quant: false }), }, - { label: 'Qwen2.5 3B Quantized', value: MODEL_REGISTRY.LLM.QWEN2_5_3B }, + { label: 'Qwen2.5 3B Quantized', value: models.llm.qwen2_5_3b() }, // Qwen3.5 - { label: 'Qwen3.5 0.8B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_5_0_8B }, - { label: 'Qwen3.5 2B Quantized', value: MODEL_REGISTRY.LLM.QWEN3_5_2B }, + { label: 'Qwen3.5 0.8B Quantized', value: models.llm.qwen3_5_0_8b() }, + { label: 'Qwen3.5 2B Quantized', value: models.llm.qwen3_5_2b() }, // Phi-4 { label: 'Phi-4 Mini 4B', - value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B({ quant: false }), + value: models.llm.phi_4_mini_4b({ quant: false }), }, { label: 'Phi-4 Mini 4B Quantized', - value: MODEL_REGISTRY.LLM.PHI_4_MINI_4B, + value: models.llm.phi_4_mini_4b(), }, // LFM2.5 { label: 'LFM2.5 350M', - value: MODEL_REGISTRY.LLM.LFM2_5_350M({ quant: false }), + value: models.llm.lfm2_5_350m({ quant: false }), }, - { label: 'LFM2.5 350M Quantized', value: MODEL_REGISTRY.LLM.LFM2_5_350M }, + { label: 'LFM2.5 350M Quantized', value: models.llm.lfm2_5_350m() }, { label: 'LFM2.5 1.2B Instruct', - value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT({ quant: false }), + value: models.llm.lfm2_5_1_2b_instruct({ quant: false }), }, { label: 'LFM2.5 1.2B Instruct Quantized', - value: MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT, + value: models.llm.lfm2_5_1_2b_instruct(), }, // Bielik v3.0 { label: 'Bielik v3.0 1.5B', - value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B({ quant: false }), + value: models.llm.bielik_v3_0_1_5b({ quant: false }), }, { label: 'Bielik v3.0 1.5B Quantized', - value: MODEL_REGISTRY.LLM.BIELIK_V3_0_1_5B, + value: models.llm.bielik_v3_0_1_5b(), }, ]; diff --git a/apps/speech/components/ModelPicker.tsx b/apps/speech/components/ModelPicker.tsx index 22de4fc70b..5e8284ee9a 100644 --- a/apps/speech/components/ModelPicker.tsx +++ b/apps/speech/components/ModelPicker.tsx @@ -23,17 +23,6 @@ type Props = { const DROPDOWN_MAX_HEIGHT = 200; -// MODEL_REGISTRY accessors are functions, so passing them to useState makes -// React auto-invoke them as lazy initializers — state becomes the underlying -// config object, breaking reference equality against the accessor in MODELS. -// Match by modelName when both sides expose one, otherwise fall back to ===. -function sameValue(a: T, b: T): boolean { - const am = (a as { modelName?: unknown })?.modelName; - const bm = (b as { modelName?: unknown })?.modelName; - if (typeof am === 'string' && typeof bm === 'string') return am === bm; - return a === b; -} - export function ModelPicker({ models, selectedModel, @@ -45,7 +34,7 @@ export function ModelPicker({ const [triggerHeight, setTriggerHeight] = useState(0); const [expandUp, setExpandUp] = useState(false); const triggerRef = useRef>(null); - const selected = models.find((m) => sameValue(m.value, selectedModel)); + const selected = models.find((m) => m.value === selectedModel); useEffect(() => { if (disabled) setOpen(false); @@ -98,7 +87,7 @@ export function ModelPicker({ keyboardShouldPersistTaps="handled" > {models.map((item) => { - const isSelected = sameValue(item.value, selectedModel); + const isSelected = item.value === selectedModel; return ( [] = [ { label: 'Whisper Tiny', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }), + value: models.speech_to_text.whisper_tiny_en({ quant: false }), }, { label: 'Whisper Tiny Q', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN, + value: models.speech_to_text.whisper_tiny_en(), }, { label: 'Whisper Base', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_BASE_EN, + value: models.speech_to_text.whisper_base_en(), }, { label: 'Whisper Small', - value: MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_SMALL_EN, + value: models.speech_to_text.whisper_small_en(), }, ]; import FontAwesome from '@expo/vector-icons/FontAwesome'; @@ -56,7 +56,7 @@ const isSimulator = DeviceInfo.isEmulatorSync(); export const SpeechToTextScreen = ({ onBack }: { onBack: () => void }) => { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN({ quant: false }) + models.speech_to_text.whisper_tiny_en({ quant: false }) ); const model = useSpeechToText({ diff --git a/apps/text-embeddings/app/clip-embeddings/index.tsx b/apps/text-embeddings/app/clip-embeddings/index.tsx index 7e3f173f5e..2f37dffecd 100644 --- a/apps/text-embeddings/app/clip-embeddings/index.tsx +++ b/apps/text-embeddings/app/clip-embeddings/index.tsx @@ -13,7 +13,7 @@ import { } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { - MODEL_REGISTRY, + models, useTextEmbeddings, useImageEmbeddings, ImageEmbeddingsProps, @@ -24,11 +24,11 @@ type ImageEmbeddingModel = ImageEmbeddingsProps['model']; const IMAGE_MODELS: { label: string; value: ImageEmbeddingModel }[] = [ { label: 'ViT-B/32 Quantized', - value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE, + value: models.image_embedding.clip_vit_base_patch32_image(), }, { label: 'ViT-B/32 FP32', - value: MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE({ + value: models.image_embedding.clip_vit_base_patch32_image({ quant: false, }), }, @@ -55,11 +55,11 @@ export default function ClipEmbeddingsScreenWrapper() { function ClipEmbeddingsScreen() { const [selectedImageModel, setSelectedImageModel] = useState( - MODEL_REGISTRY.IMAGE_EMBEDDING.CLIP_VIT_BASE_PATCH32_IMAGE + models.image_embedding.clip_vit_base_patch32_image() ); const textModel = useTextEmbeddings({ - model: MODEL_REGISTRY.TEXT_EMBEDDING.CLIP_VIT_BASE_PATCH32_TEXT, + model: models.text_embedding.clip_vit_base_patch32_text(), }); const imageModel = useImageEmbeddings({ model: selectedImageModel }); diff --git a/apps/text-embeddings/app/text-embeddings/index.tsx b/apps/text-embeddings/app/text-embeddings/index.tsx index 90f059a51a..fe1514bd9b 100644 --- a/apps/text-embeddings/app/text-embeddings/index.tsx +++ b/apps/text-embeddings/app/text-embeddings/index.tsx @@ -13,7 +13,7 @@ import { import { Ionicons } from '@expo/vector-icons'; import { ModelPicker } from '../../components/ModelPicker'; import { - MODEL_REGISTRY, + models, useTextEmbeddings, TextEmbeddingsProps, } from 'react-native-executorch'; @@ -21,32 +21,34 @@ import { type TextEmbeddingModel = TextEmbeddingsProps['model']; const MODELS: { label: string; value: TextEmbeddingModel }[] = [ - { label: 'MiniLM L6', value: MODEL_REGISTRY.TEXT_EMBEDDING.ALL_MINILM_L6_V2 }, + { label: 'MiniLM L6', value: models.text_embedding.all_minilm_l6_v2() }, { label: 'MPNet Base', - value: MODEL_REGISTRY.TEXT_EMBEDDING.ALL_MPNET_BASE_V2, + value: models.text_embedding.all_mpnet_base_v2(), }, { label: 'MultiQA MiniLM', - value: MODEL_REGISTRY.TEXT_EMBEDDING.MULTI_QA_MINILM_L6_COS_V1, + value: models.text_embedding.multi_qa_minilm_l6_cos_v1(), }, { label: 'MultiQA MPNet', - value: MODEL_REGISTRY.TEXT_EMBEDDING.MULTI_QA_MPNET_BASE_DOT_V1, + value: models.text_embedding.multi_qa_mpnet_base_dot_v1(), }, { - label: 'Multilingual DistilUSE (8da4w)', - value: - MODEL_REGISTRY.TEXT_EMBEDDING.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W, + label: 'Multilingual DistilUSE (xnnpack)', + value: models.text_embedding.distiluse_base_multilingual_cased_v2({ + backend: 'xnnpack', + }), }, { label: 'Multilingual DistilUSE (CoreML)', - value: - MODEL_REGISTRY.TEXT_EMBEDDING.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML, + value: models.text_embedding.distiluse_base_multilingual_cased_v2({ + backend: 'coreml', + }), }, { label: 'Multilingual Paraphrase (8da4w)', - value: MODEL_REGISTRY.TEXT_EMBEDDING.PARAPHRASE_MULTILINGUAL_MINILM_L12_V2, + value: models.text_embedding.paraphrase_multilingual_minilm_l12_v2(), }, ]; import { useIsFocused } from '@react-navigation/native'; @@ -61,7 +63,7 @@ export default function TextEmbeddingsScreenWrapper() { function TextEmbeddingsScreen() { const [selectedModel, setSelectedModel] = useState( - MODEL_REGISTRY.TEXT_EMBEDDING.ALL_MINILM_L6_V2 + models.text_embedding.all_minilm_l6_v2() ); const model = useTextEmbeddings({ model: selectedModel }); const [error, setError] = useState(null); diff --git a/apps/text-embeddings/components/ModelPicker.tsx b/apps/text-embeddings/components/ModelPicker.tsx index 483532f29a..94a848596e 100644 --- a/apps/text-embeddings/components/ModelPicker.tsx +++ b/apps/text-embeddings/components/ModelPicker.tsx @@ -24,17 +24,6 @@ type Props = { const DROPDOWN_MAX_HEIGHT = 200; -// MODEL_REGISTRY accessors are functions, so passing them to useState makes -// React auto-invoke them as lazy initializers — state becomes the underlying -// config object, breaking reference equality against the accessor in MODELS. -// Match by modelName when both sides expose one, otherwise fall back to ===. -function sameValue(a: T, b: T): boolean { - const am = (a as { modelName?: unknown })?.modelName; - const bm = (b as { modelName?: unknown })?.modelName; - if (typeof am === 'string' && typeof bm === 'string') return am === bm; - return a === b; -} - export function ModelPicker({ models, selectedModel, @@ -47,7 +36,7 @@ export function ModelPicker({ const [expandUp, setExpandUp] = useState(false); const [dropdownTop, setDropdownTop] = useState(0); const triggerRef = useRef>(null); - const selected = models.find((m) => sameValue(m.value, selectedModel)); + const selected = models.find((m) => m.value === selectedModel); useEffect(() => { if (disabled) setOpen(false); @@ -123,7 +112,7 @@ export function ModelPicker({ showsVerticalScrollIndicator={true} > {models.map((item) => { - const isSelected = sameValue(item.value, selectedModel); + const isSelected = item.value === selectedModel; return ( = { }; ``` -- `quant` defaults to the quantized variant for models that publish one (e.g. `LLAMA3_2_3B` → SpinQuant, `EFFICIENTNET_V2_S` → int8). Pass `{ quant: false }` to get the full-precision variant. For models with a single variant, `quant` is accepted but has no effect. -- `backend` selects an explicit backend. The accessor's call signature is typed to exactly the backends the model ships with, so requesting one the model doesn't publish is a compile-time error (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ backend: 'coreml' })` does not type-check — Llama 3.2 is xnnpack-only). When `backend` is omitted, the platform-default applies (typically CoreML on iOS and XNNPACK on Android for multi-backend models). +- `quant` defaults to the quantized variant for models that publish one (e.g. `llama3_2_3b` → SpinQuant, `efficientnet_v2_s` → int8). Pass `{ quant: false }` to get the full-precision variant. For models with a single variant, `quant` is accepted but has no effect. +- `backend` selects an explicit backend. The accessor's call signature is typed to exactly the backends the model ships with, so requesting one the model doesn't publish is a compile-time error (e.g. `models.llm.llama3_2_3b({ backend: 'coreml' })` does not type-check — Llama 3.2 is xnnpack-only). When `backend` is omitted, the platform-default applies (typically CoreML on iOS and XNNPACK on Android for multi-backend models). ## Usage patterns ### Default model ```typescript -import { MODEL_REGISTRY } from 'react-native-executorch'; - -const llm = useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B); -const classifier = useClassification( - MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S -); -const speechToText = useSpeechToText( - MODEL_REGISTRY.SPEECH_TO_TEXT.WHISPER_TINY_EN -); +import { models } from 'react-native-executorch'; + +const llm = useLLM({ model: models.llm.llama3_2_3b() }); +const classifier = useClassification({ + model: models.classification.efficientnet_v2_s(), +}); +const stt = useSpeechToText({ + model: models.speech_to_text.whisper_tiny_en(), +}); ``` ### Non-quantized variant ```typescript -const llm = useLLM(MODEL_REGISTRY.LLM.QWEN3_4B({ quant: false })); -const classifier = useClassification( - MODEL_REGISTRY.CLASSIFICATION.EFFICIENTNET_V2_S({ quant: false }) -); +const llm = useLLM({ model: models.llm.qwen3_4b({ quant: false }) }); +const classifier = useClassification({ + model: models.classification.efficientnet_v2_s({ quant: false }), +}); ``` ### Explicit backend @@ -75,50 +79,63 @@ const classifier = useClassification( ```typescript // Force XNNPACK on iOS (overrides the CoreML default). const detector = useObjectDetection({ - model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO({ backend: 'xnnpack' }), + model: models.object_detection.rf_detr_nano({ backend: 'xnnpack' }), }); // Combine `quant` and `backend`. -const styled = useStyleTransfer( - MODEL_REGISTRY.STYLE_TRANSFER.CANDY({ backend: 'coreml', quant: false }) -); +const styled = useStyleTransfer({ + model: models.style_transfer.candy({ backend: 'coreml', quant: false }), +}); ``` -### Inspecting a model's config +### Text-to-speech -Accessors transparently expose the default config's fields, so you can read them without calling: +`text_to_speech` models pair with a voice. Voices have no quant/backend axis and are exposed as plain configs under `voices`. ```typescript -console.log(MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelName); -// → "llama-3.2-3b-spinquant" +import { models } from 'react-native-executorch'; + +const tts = useTextToSpeech({ + model: models.text_to_speech.kokoro_small(), + voice: models.text_to_speech.voices.af_heart, +}); +``` + +### OCR + +OCR is parameterized by language. The accessor builds the right detector + per-alphabet recognizer combo for the requested ISO language token: -console.log(MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelSource); -// → "https://huggingface.co/software-mansion/react-native-executorch-llama-3.2/resolve/v0.9.0/3b/xnnpack/llama_3_2_3b_xnnpack_spinquant.pte" +```typescript +const ocr = useOcr({ + model: models.ocr({ language: 'en' }), +}); ``` +The `language` parameter is type-narrowed to supported tokens (`'en'`, `'es'`, `'ja'`, `'ko'`, …). See the OCR docs for the full list. + ### Direct imports still work Every model is also exported as a top-level constant. Either style is supported: ```typescript -import { LFM2_5_1_2B_INSTRUCT, MODEL_REGISTRY } from 'react-native-executorch'; +import { LFM2_5_1_2B_INSTRUCT, models } from 'react-native-executorch'; -useLLM(LFM2_5_1_2B_INSTRUCT); -useLLM(MODEL_REGISTRY.LLM.LFM2_5_1_2B_INSTRUCT); +useLLM({ model: LFM2_5_1_2B_INSTRUCT }); +useLLM({ model: models.llm.lfm2_5_1_2b_instruct() }); ``` ## Migration from the previous registry -Earlier releases exposed `MODEL_REGISTRY.ALL_MODELS` as a flat dictionary of every model. That shape has been replaced with the grouped accessor above. +Earlier releases exposed `MODEL_REGISTRY` as an uppercase, dual-value/function shape. That has been replaced with a function-only, lowercase `models` export. ```typescript // Before -const names = Object.values(MODEL_REGISTRY.ALL_MODELS).map((m) => m.modelName); +useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B); +useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false })); // After -const names = Object.values(MODEL_REGISTRY) - .flatMap((group) => Object.values(group)) - .map((m) => m.modelName); +useLLM({ model: models.llm.llama3_2_3b() }); +useLLM({ model: models.llm.llama3_2_3b({ quant: false }) }); ``` -Individual constant imports (`LLAMA3_2_3B`, `WHISPER_TINY_EN`, ...) are unchanged. +Individual constant imports (`LLAMA3_2_3B`, `WHISPER_TINY_EN`, …) are unchanged. diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts index 1120b1992c..1215e96b03 100644 --- a/packages/react-native-executorch/src/constants/modelRegistry.ts +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -1,20 +1,33 @@ import { Platform } from 'react-native'; import * as M from './modelUrls'; +import * as OCR from './ocr/models'; +import { symbols } from './ocr/symbols'; +import { KOKORO_SMALL, KOKORO_MEDIUM } from './tts/models'; +import { + KOKORO_VOICE_AF_HEART, + KOKORO_VOICE_AF_RIVER, + KOKORO_VOICE_AF_SARAH, + KOKORO_VOICE_AM_ADAM, + KOKORO_VOICE_AM_MICHAEL, + KOKORO_VOICE_AM_SANTA, + KOKORO_VOICE_BF_EMMA, + KOKORO_VOICE_BM_DANIEL, +} from './tts/voices'; /** - * Backend options accepted by `MODEL_REGISTRY` accessors. + * Backend options accepted by `models` accessors. * * The set of backends a particular model can be loaded with is encoded in - * its accessor's call signature — e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B` - * only accepts `'xnnpack'`, while `MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO` - * accepts `'xnnpack' | 'coreml'`. Passing a backend a model doesn't ship is - * a compile-time error. + * its accessor's call signature — e.g. `models.llm.llama3_2_3b` only accepts + * `'xnnpack'`, while `models.object_detection.rf_detr_nano` accepts + * `'xnnpack' | 'coreml'`. Passing a backend a model doesn't ship is a + * compile-time error. * @category Utils */ export type Backend = 'xnnpack' | 'coreml' | 'vulkan' | 'qnn'; /** - * Options for a `MODEL_REGISTRY` accessor call. + * Options for a `models` accessor call. * @typeParam B - Subset of {@link Backend} that the accessor actually supports. * @category Utils */ @@ -25,15 +38,10 @@ export type ModelOpts = { backend?: B; }; -/** - * An accessor that behaves as the platform-default config when read as a value - * (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B.modelName`) and as a function when - * called (e.g. `MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false })`). - */ -type Accessor< - C extends { modelName: string }, - B extends Backend = Backend, -> = C & ((opts?: ModelOpts) => C); +// Accessors are functions; calling with no opts returns the platform default. +type Accessor = ( + opts?: ModelOpts +) => C; type BackendCell = { base?: { modelName: string }; @@ -116,11 +124,8 @@ function variant( ): Accessor, BackendsOf> { type C = ConfigOf; type B = BackendsOf; - const defaultConfig = resolveVariant(variants, platformDefaults, {}) as C; - const fn = ((opts: ModelOpts = {}) => - resolveVariant(variants, platformDefaults, opts) as C) as Accessor; - Object.assign(fn, defaultConfig); - return fn; + return (opts: ModelOpts = {}) => + resolveVariant(variants, platformDefaults, opts) as C; } // Single-config accessor (xnnpack-only, no quantized variant). @@ -137,12 +142,7 @@ function pair( } // ───────────────────────────────────────────────────────────────────────────── -// Per-backend variant maps for the models that ship more than one backend. -// -// Kept inline (rather than as new top-level constants in `modelUrls.ts`) so -// the (quant × backend) matrix lives next to the registry that consumes it. -// The Platform.OS-collapsed exports in `modelUrls.ts` remain the back-compat -// top-level imports. +// Per-backend variant maps for models that ship more than one backend. // ───────────────────────────────────────────────────────────────────────────── const EFFICIENTNET_V2_S_VARIANTS = { @@ -314,162 +314,201 @@ const DISTILUSE_BASE_MULTILINGUAL_CASED_V2_VARIANTS = { const COREML_ON_IOS = { ios: 'coreml', default: 'xnnpack' } as const; +// ───────────────────────────────────────────────────────────────────────────── +// OCR — language-parameterized accessor. +// +// The OCR pipeline ships one CRAFT detector + per-alphabet CRNN recognizers, +// already paired up in `OCR_` objects keyed by ISO language token +// (the `.language` field on each export). Build a runtime map from those +// exports so the user only needs to pass `{ language: 'en' }`. +// ───────────────────────────────────────────────────────────────────────────── + +type OcrConfig = typeof OCR.OCR_ABAZA; +type SupportedLanguage = keyof typeof symbols; + +const OCR_BY_LANGUAGE: Partial> = (() => { + const map: Partial> = {}; + for (const value of Object.values(OCR) as OcrConfig[]) { + if (value && typeof value === 'object' && 'language' in value) { + map[value.language as SupportedLanguage] = value; + } + } + return map; +})(); + +function ocr({ language }: { language: SupportedLanguage }): OcrConfig { + const cfg = OCR_BY_LANGUAGE[language]; + if (!cfg) { + throw new Error( + `OCR is not published for language '${language}'. ` + + `Supported: ${Object.keys(OCR_BY_LANGUAGE).sort().join(', ')}` + ); + } + return cfg; +} + /** - * Typed model registry grouped by capability. Each entry exposes the model's - * platform-default config and accepts `{ quant, backend }` for per-variant - * selection. The `backend` parameter is typed to exactly the backends a given + * Typed model registry grouped by capability. Each entry is a function-only + * accessor: call it (optionally with `{ quant, backend }`) to get the resolved + * config. The `backend` parameter is typed to exactly the backends a given * model ships with — asking for a backend a model doesn't publish is a * compile-time error. * @example * ```ts - * import { MODEL_REGISTRY } from 'react-native-executorch'; + * import { models } from 'react-native-executorch'; * - * // Platform default (coreml on iOS, xnnpack on Android for multi-backend models). - * useObjectDetection({ model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO }); + * // Platform default (CoreML on iOS, XNNPACK on Android for multi-backend models). + * useObjectDetection({ model: models.object_detection.rf_detr_nano() }); * * // Explicit backend. * useObjectDetection({ - * model: MODEL_REGISTRY.OBJECT_DETECTION.RF_DETR_NANO({ backend: 'xnnpack' }), + * model: models.object_detection.rf_detr_nano({ backend: 'xnnpack' }), * }); * * // Non-quantized variant. - * useLLM(MODEL_REGISTRY.LLM.LLAMA3_2_3B({ quant: false })); + * useLLM({ model: models.llm.llama3_2_3b({ quant: false }) }); + * + * // OCR — language-parameterized. + * useOcr({ model: models.ocr({ language: 'en' }) }); * ``` * @category Utils */ -export const MODEL_REGISTRY = { - LLM: { - LLAMA3_2_1B: pair(M.LLAMA3_2_1B, M.LLAMA3_2_1B_SPINQUANT), - LLAMA3_2_3B: pair(M.LLAMA3_2_3B, M.LLAMA3_2_3B_SPINQUANT), - QWEN3_0_6B: pair(M.QWEN3_0_6B, M.QWEN3_0_6B_QUANTIZED), - QWEN3_1_7B: pair(M.QWEN3_1_7B, M.QWEN3_1_7B_QUANTIZED), - QWEN3_4B: pair(M.QWEN3_4B, M.QWEN3_4B_QUANTIZED), - QWEN3_5_0_8B: base(M.QWEN3_5_0_8B_QUANTIZED), - QWEN3_5_2B: base(M.QWEN3_5_2B_QUANTIZED), - QWEN2_5_0_5B: pair(M.QWEN2_5_0_5B, M.QWEN2_5_0_5B_QUANTIZED), - QWEN2_5_1_5B: pair(M.QWEN2_5_1_5B, M.QWEN2_5_1_5B_QUANTIZED), - QWEN2_5_3B: pair(M.QWEN2_5_3B, M.QWEN2_5_3B_QUANTIZED), - HAMMER2_1_0_5B: pair(M.HAMMER2_1_0_5B, M.HAMMER2_1_0_5B_QUANTIZED), - HAMMER2_1_1_5B: pair(M.HAMMER2_1_1_5B, M.HAMMER2_1_1_5B_QUANTIZED), - HAMMER2_1_3B: pair(M.HAMMER2_1_3B, M.HAMMER2_1_3B_QUANTIZED), - SMOLLM2_1_135M: pair(M.SMOLLM2_1_135M, M.SMOLLM2_1_135M_QUANTIZED), - SMOLLM2_1_360M: pair(M.SMOLLM2_1_360M, M.SMOLLM2_1_360M_QUANTIZED), - SMOLLM2_1_1_7B: pair(M.SMOLLM2_1_1_7B, M.SMOLLM2_1_1_7B_QUANTIZED), - PHI_4_MINI_4B: pair(M.PHI_4_MINI_4B, M.PHI_4_MINI_4B_QUANTIZED), - LFM2_5_350M: pair(M.LFM2_5_350M, M.LFM2_5_350M_QUANTIZED), - LFM2_5_1_2B_INSTRUCT: pair( +export const models = { + llm: { + llama3_2_1b: pair(M.LLAMA3_2_1B, M.LLAMA3_2_1B_SPINQUANT), + llama3_2_3b: pair(M.LLAMA3_2_3B, M.LLAMA3_2_3B_SPINQUANT), + qwen3_0_6b: pair(M.QWEN3_0_6B, M.QWEN3_0_6B_QUANTIZED), + qwen3_1_7b: pair(M.QWEN3_1_7B, M.QWEN3_1_7B_QUANTIZED), + qwen3_4b: pair(M.QWEN3_4B, M.QWEN3_4B_QUANTIZED), + qwen3_5_0_8b: base(M.QWEN3_5_0_8B_QUANTIZED), + qwen3_5_2b: base(M.QWEN3_5_2B_QUANTIZED), + qwen2_5_0_5b: pair(M.QWEN2_5_0_5B, M.QWEN2_5_0_5B_QUANTIZED), + qwen2_5_1_5b: pair(M.QWEN2_5_1_5B, M.QWEN2_5_1_5B_QUANTIZED), + qwen2_5_3b: pair(M.QWEN2_5_3B, M.QWEN2_5_3B_QUANTIZED), + hammer2_1_0_5b: pair(M.HAMMER2_1_0_5B, M.HAMMER2_1_0_5B_QUANTIZED), + hammer2_1_1_5b: pair(M.HAMMER2_1_1_5B, M.HAMMER2_1_1_5B_QUANTIZED), + hammer2_1_3b: pair(M.HAMMER2_1_3B, M.HAMMER2_1_3B_QUANTIZED), + smollm2_1_135m: pair(M.SMOLLM2_1_135M, M.SMOLLM2_1_135M_QUANTIZED), + smollm2_1_360m: pair(M.SMOLLM2_1_360M, M.SMOLLM2_1_360M_QUANTIZED), + smollm2_1_1_7b: pair(M.SMOLLM2_1_1_7B, M.SMOLLM2_1_1_7B_QUANTIZED), + phi_4_mini_4b: pair(M.PHI_4_MINI_4B, M.PHI_4_MINI_4B_QUANTIZED), + lfm2_5_350m: pair(M.LFM2_5_350M, M.LFM2_5_350M_QUANTIZED), + lfm2_5_1_2b_instruct: pair( M.LFM2_5_1_2B_INSTRUCT, M.LFM2_5_1_2B_INSTRUCT_QUANTIZED ), - BIELIK_V3_0_1_5B: pair(M.BIELIK_V3_0_1_5B, M.BIELIK_V3_0_1_5B_QUANTIZED), + bielik_v3_0_1_5b: pair(M.BIELIK_V3_0_1_5B, M.BIELIK_V3_0_1_5B_QUANTIZED), }, - VLM: { - LFM2_5_VL_1_6B: base(M.LFM2_5_VL_1_6B_QUANTIZED), - LFM2_5_VL_450M: base(M.LFM2_5_VL_450M_QUANTIZED), + multimodal: { + lfm2_5_vl_1_6b: base(M.LFM2_5_VL_1_6B_QUANTIZED), + lfm2_5_vl_450m: base(M.LFM2_5_VL_450M_QUANTIZED), }, - CLASSIFICATION: { - EFFICIENTNET_V2_S: variant(EFFICIENTNET_V2_S_VARIANTS, COREML_ON_IOS), - PRIVACY_FILTER_OPENAI: base(M.PRIVACY_FILTER_OPENAI), - PRIVACY_FILTER_NEMOTRON: base(M.PRIVACY_FILTER_NEMOTRON), + classification: { + efficientnet_v2_s: variant(EFFICIENTNET_V2_S_VARIANTS, COREML_ON_IOS), + privacy_filter_openai: base(M.PRIVACY_FILTER_OPENAI), + privacy_filter_nemotron: base(M.PRIVACY_FILTER_NEMOTRON), }, - OBJECT_DETECTION: { - SSDLITE_320_MOBILENET_V3_LARGE: variant( + object_detection: { + ssdlite_320_mobilenet_v3_large: variant( SSDLITE_320_MOBILENET_V3_LARGE_VARIANTS, COREML_ON_IOS ), - RF_DETR_NANO: variant(RF_DETR_NANO_VARIANTS, COREML_ON_IOS), - YOLO26N: base(M.YOLO26N), - YOLO26S: base(M.YOLO26S), - YOLO26M: base(M.YOLO26M), - YOLO26L: base(M.YOLO26L), - YOLO26X: base(M.YOLO26X), - FASTSAM_S: variant(FASTSAM_S_VARIANTS, COREML_ON_IOS), - FASTSAM_X: variant(FASTSAM_X_VARIANTS, COREML_ON_IOS), + rf_detr_nano: variant(RF_DETR_NANO_VARIANTS, COREML_ON_IOS), + yolo26n: base(M.YOLO26N), + yolo26s: base(M.YOLO26S), + yolo26m: base(M.YOLO26M), + yolo26l: base(M.YOLO26L), + yolo26x: base(M.YOLO26X), + fastsam_s: variant(FASTSAM_S_VARIANTS, COREML_ON_IOS), + fastsam_x: variant(FASTSAM_X_VARIANTS, COREML_ON_IOS), }, - SEMANTIC_SEGMENTATION: { - DEEPLAB_V3_RESNET50: pair( + semantic_segmentation: { + deeplab_v3_resnet50: pair( M.DEEPLAB_V3_RESNET50, M.DEEPLAB_V3_RESNET50_QUANTIZED ), - DEEPLAB_V3_RESNET101: pair( + deeplab_v3_resnet101: pair( M.DEEPLAB_V3_RESNET101, M.DEEPLAB_V3_RESNET101_QUANTIZED ), - DEEPLAB_V3_MOBILENET_V3_LARGE: pair( + deeplab_v3_mobilenet_v3_large: pair( M.DEEPLAB_V3_MOBILENET_V3_LARGE, M.DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED ), - LRASPP_MOBILENET_V3_LARGE: pair( + lraspp_mobilenet_v3_large: pair( M.LRASPP_MOBILENET_V3_LARGE, M.LRASPP_MOBILENET_V3_LARGE_QUANTIZED ), - FCN_RESNET50: pair(M.FCN_RESNET50, M.FCN_RESNET50_QUANTIZED), - FCN_RESNET101: pair(M.FCN_RESNET101, M.FCN_RESNET101_QUANTIZED), - SELFIE_SEGMENTATION: base(M.SELFIE_SEGMENTATION), + fcn_resnet50: pair(M.FCN_RESNET50, M.FCN_RESNET50_QUANTIZED), + fcn_resnet101: pair(M.FCN_RESNET101, M.FCN_RESNET101_QUANTIZED), + selfie_segmentation: base(M.SELFIE_SEGMENTATION), }, - INSTANCE_SEGMENTATION: { - YOLO26N_SEG: base(M.YOLO26N_SEG), - YOLO26S_SEG: base(M.YOLO26S_SEG), - YOLO26M_SEG: base(M.YOLO26M_SEG), - YOLO26L_SEG: base(M.YOLO26L_SEG), - YOLO26X_SEG: base(M.YOLO26X_SEG), - RF_DETR_NANO_SEG: variant(RF_DETR_NANO_SEG_VARIANTS, COREML_ON_IOS), + instance_segmentation: { + yolo26n_seg: base(M.YOLO26N_SEG), + yolo26s_seg: base(M.YOLO26S_SEG), + yolo26m_seg: base(M.YOLO26M_SEG), + yolo26l_seg: base(M.YOLO26L_SEG), + yolo26x_seg: base(M.YOLO26X_SEG), + rf_detr_nano_seg: variant(RF_DETR_NANO_SEG_VARIANTS, COREML_ON_IOS), }, - STYLE_TRANSFER: { - CANDY: variant(STYLE_TRANSFER_CANDY_VARIANTS, COREML_ON_IOS), - MOSAIC: variant(STYLE_TRANSFER_MOSAIC_VARIANTS, COREML_ON_IOS), - RAIN_PRINCESS: variant( + style_transfer: { + candy: variant(STYLE_TRANSFER_CANDY_VARIANTS, COREML_ON_IOS), + mosaic: variant(STYLE_TRANSFER_MOSAIC_VARIANTS, COREML_ON_IOS), + rain_princess: variant( STYLE_TRANSFER_RAIN_PRINCESS_VARIANTS, COREML_ON_IOS ), - UDNIE: variant(STYLE_TRANSFER_UDNIE_VARIANTS, COREML_ON_IOS), + udnie: variant(STYLE_TRANSFER_UDNIE_VARIANTS, COREML_ON_IOS), + }, + speech_to_text: { + whisper_tiny_en: pair(M.WHISPER_TINY_EN, M.WHISPER_TINY_EN_QUANTIZED), + whisper_base_en: pair(M.WHISPER_BASE_EN, M.WHISPER_BASE_EN_QUANTIZED), + whisper_small_en: pair(M.WHISPER_SMALL_EN, M.WHISPER_SMALL_EN_QUANTIZED), + whisper_tiny: base(M.WHISPER_TINY), + whisper_base: base(M.WHISPER_BASE), + whisper_small: base(M.WHISPER_SMALL), }, - SPEECH_TO_TEXT: { - WHISPER_TINY_EN: pair(M.WHISPER_TINY_EN, M.WHISPER_TINY_EN_QUANTIZED), - WHISPER_BASE_EN: pair(M.WHISPER_BASE_EN, M.WHISPER_BASE_EN_QUANTIZED), - WHISPER_SMALL_EN: pair(M.WHISPER_SMALL_EN, M.WHISPER_SMALL_EN_QUANTIZED), - WHISPER_TINY: base(M.WHISPER_TINY), - WHISPER_BASE: base(M.WHISPER_BASE), - WHISPER_SMALL: base(M.WHISPER_SMALL), + text_to_speech: { + kokoro_small: base(KOKORO_SMALL), + kokoro_medium: base(KOKORO_MEDIUM), + // Voices have no quant/backend axis; expose as plain configs. + voices: { + af_heart: KOKORO_VOICE_AF_HEART, + af_river: KOKORO_VOICE_AF_RIVER, + af_sarah: KOKORO_VOICE_AF_SARAH, + am_adam: KOKORO_VOICE_AM_ADAM, + am_michael: KOKORO_VOICE_AM_MICHAEL, + am_santa: KOKORO_VOICE_AM_SANTA, + bf_emma: KOKORO_VOICE_BF_EMMA, + bm_daniel: KOKORO_VOICE_BM_DANIEL, + }, }, - TEXT_EMBEDDING: { - ALL_MINILM_L6_V2: base(M.ALL_MINILM_L6_V2), - ALL_MPNET_BASE_V2: base(M.ALL_MPNET_BASE_V2), - MULTI_QA_MINILM_L6_COS_V1: base(M.MULTI_QA_MINILM_L6_COS_V1), - MULTI_QA_MPNET_BASE_DOT_V1: base(M.MULTI_QA_MPNET_BASE_DOT_V1), - DISTILUSE_BASE_MULTILINGUAL_CASED_V2: variant( + text_embedding: { + all_minilm_l6_v2: base(M.ALL_MINILM_L6_V2), + all_mpnet_base_v2: base(M.ALL_MPNET_BASE_V2), + multi_qa_minilm_l6_cos_v1: base(M.MULTI_QA_MINILM_L6_COS_V1), + multi_qa_mpnet_base_dot_v1: base(M.MULTI_QA_MPNET_BASE_DOT_V1), + distiluse_base_multilingual_cased_v2: variant( DISTILUSE_BASE_MULTILINGUAL_CASED_V2_VARIANTS, COREML_ON_IOS ), - /** - * @deprecated Use `DISTILUSE_BASE_MULTILINGUAL_CASED_V2` and either omit - * `backend` (defaults to xnnpack on Android) or pass `{ backend: 'xnnpack' }`. - */ - DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W: base( - M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W - ), - /** - * @deprecated Use `DISTILUSE_BASE_MULTILINGUAL_CASED_V2({ backend: 'coreml' })`. - */ - DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML: base( - M.DISTILUSE_BASE_MULTILINGUAL_CASED_V2_COREML - ), - PARAPHRASE_MULTILINGUAL_MINILM_L12_V2: base( + paraphrase_multilingual_minilm_l12_v2: base( M.PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED ), - CLIP_VIT_BASE_PATCH32_TEXT: base(M.CLIP_VIT_BASE_PATCH32_TEXT), + clip_vit_base_patch32_text: base(M.CLIP_VIT_BASE_PATCH32_TEXT), }, - IMAGE_EMBEDDING: { - CLIP_VIT_BASE_PATCH32_IMAGE: pair( + image_embedding: { + clip_vit_base_patch32_image: pair( M.CLIP_VIT_BASE_PATCH32_IMAGE, M.CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED ), }, - IMAGE_GENERATION: { - BK_SDM_TINY_VPRED_512: base(M.BK_SDM_TINY_VPRED_512), - BK_SDM_TINY_VPRED_256: base(M.BK_SDM_TINY_VPRED_256), + image_generation: { + bk_sdm_tiny_vpred_512: base(M.BK_SDM_TINY_VPRED_512), + bk_sdm_tiny_vpred_256: base(M.BK_SDM_TINY_VPRED_256), }, - VAD: { - FSMN_VAD: base(M.FSMN_VAD), + vad: { + fsmn_vad: base(M.FSMN_VAD), }, + ocr, } as const; From cf16a15bec661ea56f8bdabdcdf6db5daa3e05ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Mon, 18 May 2026 18:11:46 +0200 Subject: [PATCH 13/16] chore(apps): destructure heavily-used \`models\` groups for readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per Kuba's review on #1148 — hoist a camelCase alias for any group used ≥ 2 times in a file, e.g. const instanceSegmentation = models.instance_segmentation; const objectDetection = models.object_detection; Then \`models.instance_segmentation.yolo26n_seg()\` becomes \`instanceSegmentation.yolo26n_seg()\`. Applied to 14 files where it actually reduces noise. Skips aliasing when the camelCase name would shadow an existing local identifier — common in the LLM/STT/embeddings screens where \`llm\`, \`speechToText\`, \`imageEmbedding\` etc. already name hook return values or temporaries. --- .../app/classification/index.tsx | 9 +-- .../app/instance_segmentation/index.tsx | 20 ++--- .../app/object_detection/index.tsx | 19 +++-- .../app/segment_anything/index.tsx | 9 +-- .../app/semantic_segmentation/index.tsx | 17 ++-- .../app/style_transfer/index.tsx | 11 +-- .../app/text_to_image/index.tsx | 7 +- .../tasks/InstanceSegmentationTask.tsx | 10 ++- .../tasks/ObjectDetectionTask.tsx | 7 +- .../vision_camera/tasks/SegmentationTask.tsx | 15 ++-- .../vision_camera/tasks/StyleTransferTask.tsx | 5 +- apps/llm/components/llmModels.ts | 77 ++++++++++--------- apps/speech/screens/SpeechToTextScreen.tsx | 11 +-- .../app/text-embeddings/index.tsx | 17 ++-- 14 files changed, 122 insertions(+), 112 deletions(-) diff --git a/apps/computer-vision/app/classification/index.tsx b/apps/computer-vision/app/classification/index.tsx index e2e9e3985e..55a42f7422 100644 --- a/apps/computer-vision/app/classification/index.tsx +++ b/apps/computer-vision/app/classification/index.tsx @@ -6,15 +6,16 @@ import { ClassificationModelSources, } from 'react-native-executorch'; import { ModelPicker, ModelOption } from '../../components/ModelPicker'; +const classification = models.classification; const MODELS: ModelOption[] = [ { label: 'EfficientNet V2 S Quantized', - value: models.classification.efficientnet_v2_s(), + value: classification.efficientnet_v2_s(), }, { label: 'EfficientNet V2 S', - value: models.classification.efficientnet_v2_s({ quant: false }), + value: classification.efficientnet_v2_s({ quant: false }), }, ]; import { View, StyleSheet, Image, Text, ScrollView } from 'react-native'; @@ -27,9 +28,7 @@ import ErrorBanner from '../../components/ErrorBanner'; export default function ClassificationScreen() { const [selectedModel, setSelectedModel] = - useState( - models.classification.efficientnet_v2_s() - ); + useState(classification.efficientnet_v2_s()); const [results, setResults] = useState<{ label: string; score: number }[]>( [] ); diff --git a/apps/computer-vision/app/instance_segmentation/index.tsx b/apps/computer-vision/app/instance_segmentation/index.tsx index 62cfd249df..72a4c64506 100644 --- a/apps/computer-vision/app/instance_segmentation/index.tsx +++ b/apps/computer-vision/app/instance_segmentation/index.tsx @@ -22,25 +22,27 @@ import ImageWithMasks, { DisplayInstance, } from '../../components/ImageWithMasks'; import { StatsBar } from '../../components/StatsBar'; +const instanceSegmentation = models.instance_segmentation; +const objectDetection = models.object_detection; const MODELS: ModelOption[] = [ - { label: 'Yolo26N', value: models.instance_segmentation.yolo26n_seg() }, - { label: 'Yolo26S', value: models.instance_segmentation.yolo26s_seg() }, - { label: 'Yolo26M', value: models.instance_segmentation.yolo26m_seg() }, - { label: 'Yolo26L', value: models.instance_segmentation.yolo26l_seg() }, - { label: 'Yolo26X', value: models.instance_segmentation.yolo26x_seg() }, + { label: 'Yolo26N', value: instanceSegmentation.yolo26n_seg() }, + { label: 'Yolo26S', value: instanceSegmentation.yolo26s_seg() }, + { label: 'Yolo26M', value: instanceSegmentation.yolo26m_seg() }, + { label: 'Yolo26L', value: instanceSegmentation.yolo26l_seg() }, + { label: 'Yolo26X', value: instanceSegmentation.yolo26x_seg() }, { label: 'RF-DeTR Nano', - value: models.instance_segmentation.rf_detr_nano_seg(), + value: instanceSegmentation.rf_detr_nano_seg(), }, - { label: 'FastSAM-S', value: models.object_detection.fastsam_s() }, - { label: 'FastSAM-X', value: models.object_detection.fastsam_x() }, + { label: 'FastSAM-S', value: objectDetection.fastsam_s() }, + { label: 'FastSAM-X', value: objectDetection.fastsam_x() }, ]; export default function InstanceSegmentationScreen() { const [selectedModel, setSelectedModel] = useState( - models.instance_segmentation.yolo26n_seg() + instanceSegmentation.yolo26n_seg() ); const [inferenceTime, setInferenceTime] = useState(null); diff --git a/apps/computer-vision/app/object_detection/index.tsx b/apps/computer-vision/app/object_detection/index.tsx index a21936c574..1ed3c136ba 100644 --- a/apps/computer-vision/app/object_detection/index.tsx +++ b/apps/computer-vision/app/object_detection/index.tsx @@ -14,21 +14,22 @@ import React, { useContext, useEffect, useState } from 'react'; import { GeneratingContext } from '../../context'; import ScreenWrapper from '../../ScreenWrapper'; import { StatsBar } from '../../components/StatsBar'; +const objectDetection = models.object_detection; const MODELS: ModelOption[] = [ { label: 'RF-DeTR Nano', - value: models.object_detection.rf_detr_nano(), + value: objectDetection.rf_detr_nano(), }, { label: 'SSDLite MobileNet', - value: models.object_detection.ssdlite_320_mobilenet_v3_large(), + value: objectDetection.ssdlite_320_mobilenet_v3_large(), }, - { label: 'YOLO26N', value: models.object_detection.yolo26n() }, - { label: 'YOLO26S', value: models.object_detection.yolo26s() }, - { label: 'YOLO26M', value: models.object_detection.yolo26m() }, - { label: 'YOLO26L', value: models.object_detection.yolo26l() }, - { label: 'YOLO26X', value: models.object_detection.yolo26x() }, + { label: 'YOLO26N', value: objectDetection.yolo26n() }, + { label: 'YOLO26S', value: objectDetection.yolo26s() }, + { label: 'YOLO26M', value: objectDetection.yolo26m() }, + { label: 'YOLO26L', value: objectDetection.yolo26l() }, + { label: 'YOLO26X', value: objectDetection.yolo26x() }, ]; import ErrorBanner from '../../components/ErrorBanner'; @@ -41,9 +42,7 @@ export default function ObjectDetectionScreen() { height: number; }>(); const [selectedModel, setSelectedModel] = - useState( - models.object_detection.rf_detr_nano() - ); + useState(objectDetection.rf_detr_nano()); const [inferenceTime, setInferenceTime] = useState(null); const model = useObjectDetection({ model: selectedModel }); diff --git a/apps/computer-vision/app/segment_anything/index.tsx b/apps/computer-vision/app/segment_anything/index.tsx index f8bf50fd3a..b4101309c0 100644 --- a/apps/computer-vision/app/segment_anything/index.tsx +++ b/apps/computer-vision/app/segment_anything/index.tsx @@ -45,21 +45,20 @@ import ImageWithMasks, { } from '../../components/ImageWithMasks'; import { getImage } from '../../utils'; import ColorPalette from '../../colors'; +const objectDetection = models.object_detection; type PromptMode = 'point' | 'box' | 'text'; const MODELS: ModelOption[] = [ - { label: 'FastSAM-S', value: models.object_detection.fastsam_s() }, - { label: 'FastSAM-X', value: models.object_detection.fastsam_x() }, + { label: 'FastSAM-S', value: objectDetection.fastsam_s() }, + { label: 'FastSAM-X', value: objectDetection.fastsam_x() }, ]; export default function SegmentAnythingScreen() { const { setGlobalGenerating } = useContext(GeneratingContext); const [selectedModel, setSelectedModel] = - useState( - models.object_detection.fastsam_s() - ); + useState(objectDetection.fastsam_s()); const [mode, setMode] = useState('point'); const [inferenceTime, setInferenceTime] = useState(null); diff --git a/apps/computer-vision/app/semantic_segmentation/index.tsx b/apps/computer-vision/app/semantic_segmentation/index.tsx index 5f969d83e2..f77c8de9c8 100644 --- a/apps/computer-vision/app/semantic_segmentation/index.tsx +++ b/apps/computer-vision/app/semantic_segmentation/index.tsx @@ -21,6 +21,7 @@ import { GeneratingContext } from '../../context'; import ScreenWrapper from '../../ScreenWrapper'; import { StatsBar } from '../../components/StatsBar'; import ErrorBanner from '../../components/ErrorBanner'; +const semanticSegmentation = models.semantic_segmentation; const numberToColor: number[][] = [ [255, 87, 51], // 0 Red @@ -49,31 +50,31 @@ const numberToColor: number[][] = [ const MODELS: ModelOption[] = [ { label: 'DeepLab MobileNet', - value: models.semantic_segmentation.deeplab_v3_mobilenet_v3_large(), + value: semanticSegmentation.deeplab_v3_mobilenet_v3_large(), }, { label: 'DeepLab ResNet50', - value: models.semantic_segmentation.deeplab_v3_resnet50(), + value: semanticSegmentation.deeplab_v3_resnet50(), }, { label: 'DeepLab ResNet101', - value: models.semantic_segmentation.deeplab_v3_resnet101(), + value: semanticSegmentation.deeplab_v3_resnet101(), }, { label: 'LRASPP MobileNet', - value: models.semantic_segmentation.lraspp_mobilenet_v3_large(), + value: semanticSegmentation.lraspp_mobilenet_v3_large(), }, { label: 'FCN ResNet50', - value: models.semantic_segmentation.fcn_resnet50(), + value: semanticSegmentation.fcn_resnet50(), }, { label: 'FCN ResNet101', - value: models.semantic_segmentation.fcn_resnet101(), + value: semanticSegmentation.fcn_resnet101(), }, { label: 'Selfie Segmentation', - value: models.semantic_segmentation.selfie_segmentation(), + value: semanticSegmentation.selfie_segmentation(), }, ]; @@ -81,7 +82,7 @@ export default function SemanticSegmentationScreen() { const { setGlobalGenerating } = useContext(GeneratingContext); const [selectedModel, setSelectedModel] = useState( - models.semantic_segmentation.deeplab_v3_mobilenet_v3_large() + semanticSegmentation.deeplab_v3_mobilenet_v3_large() ); const { diff --git a/apps/computer-vision/app/style_transfer/index.tsx b/apps/computer-vision/app/style_transfer/index.tsx index 4d777a3b1f..d8eda655f7 100644 --- a/apps/computer-vision/app/style_transfer/index.tsx +++ b/apps/computer-vision/app/style_transfer/index.tsx @@ -15,6 +15,7 @@ import React, { useContext, useEffect, useState } from 'react'; import { GeneratingContext } from '../../context'; import ScreenWrapper from '../../ScreenWrapper'; import { StatsBar } from '../../components/StatsBar'; +const styleTransfer = models.style_transfer; type StyleTransferModelSources = { modelName: StyleTransferModelName; @@ -22,19 +23,19 @@ type StyleTransferModelSources = { }; const MODELS: ModelOption[] = [ - { label: 'Candy', value: models.style_transfer.candy() }, - { label: 'Mosaic', value: models.style_transfer.mosaic() }, + { label: 'Candy', value: styleTransfer.candy() }, + { label: 'Mosaic', value: styleTransfer.mosaic() }, { label: 'Rain Princess', - value: models.style_transfer.rain_princess(), + value: styleTransfer.rain_princess(), }, - { label: 'Udnie', value: models.style_transfer.udnie() }, + { label: 'Udnie', value: styleTransfer.udnie() }, ]; import ErrorBanner from '../../components/ErrorBanner'; export default function StyleTransferScreen() { const [selectedModel, setSelectedModel] = useState( - models.style_transfer.candy() + styleTransfer.candy() ); const model = useStyleTransfer({ model: selectedModel }); diff --git a/apps/computer-vision/app/text_to_image/index.tsx b/apps/computer-vision/app/text_to_image/index.tsx index f2a6fd5a66..47fce1e8b6 100644 --- a/apps/computer-vision/app/text_to_image/index.tsx +++ b/apps/computer-vision/app/text_to_image/index.tsx @@ -25,17 +25,18 @@ import ProgressBar from '../../components/ProgressBar'; import { Ionicons } from '@expo/vector-icons'; import { StatsBar } from '../../components/StatsBar'; import ErrorBanner from '../../components/ErrorBanner'; +const imageGeneration = models.image_generation; type TextToImageModelSources = TextToImageProps['model']; const MODELS: ModelOption[] = [ { label: 'BK-SDM 256', - value: models.image_generation.bk_sdm_tiny_vpred_256(), + value: imageGeneration.bk_sdm_tiny_vpred_256(), }, { label: 'BK-SDM 512', - value: models.image_generation.bk_sdm_tiny_vpred_512(), + value: imageGeneration.bk_sdm_tiny_vpred_512(), }, ]; @@ -47,7 +48,7 @@ export default function TextToImageScreen() { const [input, setInput] = useState(''); const [selectedModel, setSelectedModel] = useState( - models.image_generation.bk_sdm_tiny_vpred_256() + imageGeneration.bk_sdm_tiny_vpred_256() ); const [generationTime, setGenerationTime] = useState(null); diff --git a/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx b/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx index dea843918e..478cb25732 100644 --- a/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/InstanceSegmentationTask.tsx @@ -17,6 +17,8 @@ import { buildDisplayInstances, DisplayInstance, } from '../../../components/ImageWithMasks'; +const instanceSegmentation = models.instance_segmentation; +const objectDetection = models.object_detection; type InstSegModelId = | 'instanceSegmentationYolo26n' @@ -39,19 +41,19 @@ export default function InstanceSegmentationTask({ onErrorChange, }: Props) { const yolo26n = useInstanceSegmentation({ - model: models.instance_segmentation.yolo26n_seg(), + model: instanceSegmentation.yolo26n_seg(), preventLoad: activeModel !== 'instanceSegmentationYolo26n', }); const rfdetr = useInstanceSegmentation({ - model: models.instance_segmentation.rf_detr_nano_seg(), + model: instanceSegmentation.rf_detr_nano_seg(), preventLoad: activeModel !== 'instanceSegmentationRfdetr', }); const fastsamS = useInstanceSegmentation({ - model: models.object_detection.fastsam_s(), + model: objectDetection.fastsam_s(), preventLoad: activeModel !== 'instanceSegmentationFastsamS', }); const fastsamX = useInstanceSegmentation({ - model: models.object_detection.fastsam_x(), + model: objectDetection.fastsam_x(), preventLoad: activeModel !== 'instanceSegmentationFastsamX', }); diff --git a/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx b/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx index 3885014f6f..e05de26105 100644 --- a/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/ObjectDetectionTask.tsx @@ -11,6 +11,7 @@ import { } from 'react-native-executorch'; import BoundingBoxes from '../../BoundingBoxes'; import { FRAME_TARGET_RESOLUTION, TaskProps } from './types'; +const objectDetection = models.object_detection; type ObjModelId = | 'objectDetectionSsdlite' @@ -32,15 +33,15 @@ export default function ObjectDetectionTask({ onErrorChange, }: Props) { const ssdlite = useObjectDetection({ - model: models.object_detection.ssdlite_320_mobilenet_v3_large(), + model: objectDetection.ssdlite_320_mobilenet_v3_large(), preventLoad: activeModel !== 'objectDetectionSsdlite', }); const rfdetr = useObjectDetection({ - model: models.object_detection.rf_detr_nano(), + model: objectDetection.rf_detr_nano(), preventLoad: activeModel !== 'objectDetectionRfdetr', }); const yolo26n = useObjectDetection({ - model: models.object_detection.yolo26n(), + model: objectDetection.yolo26n(), preventLoad: activeModel !== 'objectDetectionYolo26n', }); diff --git a/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx b/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx index 0b93209e22..b88e457b23 100644 --- a/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/SegmentationTask.tsx @@ -13,6 +13,7 @@ import { } from '@shopify/react-native-skia'; import { CLASS_COLORS } from '../../utils/colors'; import { FRAME_TARGET_RESOLUTION, TaskProps } from './types'; +const semanticSegmentation = models.semantic_segmentation; type SegModelId = | 'segmentationDeeplabResnet50' @@ -38,31 +39,31 @@ export default function SegmentationTask({ onErrorChange, }: Props) { const segDeeplabResnet50 = useSemanticSegmentation({ - model: models.semantic_segmentation.deeplab_v3_resnet50(), + model: semanticSegmentation.deeplab_v3_resnet50(), preventLoad: activeModel !== 'segmentationDeeplabResnet50', }); const segDeeplabResnet101 = useSemanticSegmentation({ - model: models.semantic_segmentation.deeplab_v3_resnet101(), + model: semanticSegmentation.deeplab_v3_resnet101(), preventLoad: activeModel !== 'segmentationDeeplabResnet101', }); const segDeeplabMobilenet = useSemanticSegmentation({ - model: models.semantic_segmentation.deeplab_v3_mobilenet_v3_large(), + model: semanticSegmentation.deeplab_v3_mobilenet_v3_large(), preventLoad: activeModel !== 'segmentationDeeplabMobilenet', }); const segLraspp = useSemanticSegmentation({ - model: models.semantic_segmentation.lraspp_mobilenet_v3_large(), + model: semanticSegmentation.lraspp_mobilenet_v3_large(), preventLoad: activeModel !== 'segmentationLraspp', }); const segFcnResnet50 = useSemanticSegmentation({ - model: models.semantic_segmentation.fcn_resnet50(), + model: semanticSegmentation.fcn_resnet50(), preventLoad: activeModel !== 'segmentationFcnResnet50', }); const segFcnResnet101 = useSemanticSegmentation({ - model: models.semantic_segmentation.fcn_resnet101(), + model: semanticSegmentation.fcn_resnet101(), preventLoad: activeModel !== 'segmentationFcnResnet101', }); const segSelfie = useSemanticSegmentation({ - model: models.semantic_segmentation.selfie_segmentation(), + model: semanticSegmentation.selfie_segmentation(), preventLoad: activeModel !== 'segmentationSelfie', }); diff --git a/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx b/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx index a8b72d42c3..d5f8578272 100644 --- a/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/StyleTransferTask.tsx @@ -12,6 +12,7 @@ import { SkImage, } from '@shopify/react-native-skia'; import { FRAME_TARGET_RESOLUTION, TaskProps } from './types'; +const styleTransfer = models.style_transfer; type StyleModelId = 'styleTransferCandy' | 'styleTransferMosaic'; @@ -30,11 +31,11 @@ export default function StyleTransferTask({ onErrorChange, }: Props) { const candy = useStyleTransfer({ - model: models.style_transfer.candy(), + model: styleTransfer.candy(), preventLoad: activeModel !== 'styleTransferCandy', }); const mosaic = useStyleTransfer({ - model: models.style_transfer.mosaic(), + model: styleTransfer.mosaic(), preventLoad: activeModel !== 'styleTransferMosaic', }); diff --git a/apps/llm/components/llmModels.ts b/apps/llm/components/llmModels.ts index 655b5fb019..1d80d7a395 100644 --- a/apps/llm/components/llmModels.ts +++ b/apps/llm/components/llmModels.ts @@ -5,6 +5,7 @@ import { LLMProps, } from 'react-native-executorch'; import { ModelOption } from './ModelPicker'; +const llm = models.llm; export type LLMModelSources = LLMProps['model']; @@ -12,134 +13,134 @@ export const LLM_MODELS: ModelOption[] = [ // Llama 3.2 { label: 'Llama 3.2 1B', - value: models.llm.llama3_2_1b({ quant: false }), + value: llm.llama3_2_1b({ quant: false }), }, { label: 'Llama 3.2 1B QLoRA', value: LLAMA3_2_1B_QLORA }, - { label: 'Llama 3.2 1B SpinQuant', value: models.llm.llama3_2_1b() }, + { label: 'Llama 3.2 1B SpinQuant', value: llm.llama3_2_1b() }, { label: 'Llama 3.2 3B', - value: models.llm.llama3_2_3b({ quant: false }), + value: llm.llama3_2_3b({ quant: false }), }, { label: 'Llama 3.2 3B QLoRA', value: LLAMA3_2_3B_QLORA }, - { label: 'Llama 3.2 3B SpinQuant', value: models.llm.llama3_2_3b() }, + { label: 'Llama 3.2 3B SpinQuant', value: llm.llama3_2_3b() }, // Qwen3 { label: 'Qwen3 0.6B', - value: models.llm.qwen3_0_6b({ quant: false }), + value: llm.qwen3_0_6b({ quant: false }), }, - { label: 'Qwen3 0.6B Quantized', value: models.llm.qwen3_0_6b() }, + { label: 'Qwen3 0.6B Quantized', value: llm.qwen3_0_6b() }, { label: 'Qwen3 1.7B', - value: models.llm.qwen3_1_7b({ quant: false }), + value: llm.qwen3_1_7b({ quant: false }), }, - { label: 'Qwen3 1.7B Quantized', value: models.llm.qwen3_1_7b() }, - { label: 'Qwen3 4B', value: models.llm.qwen3_4b({ quant: false }) }, - { label: 'Qwen3 4B Quantized', value: models.llm.qwen3_4b() }, + { label: 'Qwen3 1.7B Quantized', value: llm.qwen3_1_7b() }, + { label: 'Qwen3 4B', value: llm.qwen3_4b({ quant: false }) }, + { label: 'Qwen3 4B Quantized', value: llm.qwen3_4b() }, // Hammer 2.1 { label: 'Hammer 2.1 0.5B', - value: models.llm.hammer2_1_0_5b({ quant: false }), + value: llm.hammer2_1_0_5b({ quant: false }), }, { label: 'Hammer 2.1 0.5B Quantized', - value: models.llm.hammer2_1_0_5b(), + value: llm.hammer2_1_0_5b(), }, { label: 'Hammer 2.1 1.5B', - value: models.llm.hammer2_1_1_5b({ quant: false }), + value: llm.hammer2_1_1_5b({ quant: false }), }, { label: 'Hammer 2.1 1.5B Quantized', - value: models.llm.hammer2_1_1_5b(), + value: llm.hammer2_1_1_5b(), }, { label: 'Hammer 2.1 3B', - value: models.llm.hammer2_1_3b({ quant: false }), + value: llm.hammer2_1_3b({ quant: false }), }, { label: 'Hammer 2.1 3B Quantized', - value: models.llm.hammer2_1_3b(), + value: llm.hammer2_1_3b(), }, // SmolLM2 { label: 'SmolLM2 135M', - value: models.llm.smollm2_1_135m({ quant: false }), + value: llm.smollm2_1_135m({ quant: false }), }, { label: 'SmolLM2 135M Quantized', - value: models.llm.smollm2_1_135m(), + value: llm.smollm2_1_135m(), }, { label: 'SmolLM2 360M', - value: models.llm.smollm2_1_360m({ quant: false }), + value: llm.smollm2_1_360m({ quant: false }), }, { label: 'SmolLM2 360M Quantized', - value: models.llm.smollm2_1_360m(), + value: llm.smollm2_1_360m(), }, { label: 'SmolLM2 1.7B', - value: models.llm.smollm2_1_1_7b({ quant: false }), + value: llm.smollm2_1_1_7b({ quant: false }), }, { label: 'SmolLM2 1.7B Quantized', - value: models.llm.smollm2_1_1_7b(), + value: llm.smollm2_1_1_7b(), }, // Qwen2.5 { label: 'Qwen2.5 0.5B', - value: models.llm.qwen2_5_0_5b({ quant: false }), + value: llm.qwen2_5_0_5b({ quant: false }), }, { label: 'Qwen2.5 0.5B Quantized', - value: models.llm.qwen2_5_0_5b(), + value: llm.qwen2_5_0_5b(), }, { label: 'Qwen2.5 1.5B', - value: models.llm.qwen2_5_1_5b({ quant: false }), + value: llm.qwen2_5_1_5b({ quant: false }), }, { label: 'Qwen2.5 1.5B Quantized', - value: models.llm.qwen2_5_1_5b(), + value: llm.qwen2_5_1_5b(), }, { label: 'Qwen2.5 3B', - value: models.llm.qwen2_5_3b({ quant: false }), + value: llm.qwen2_5_3b({ quant: false }), }, - { label: 'Qwen2.5 3B Quantized', value: models.llm.qwen2_5_3b() }, + { label: 'Qwen2.5 3B Quantized', value: llm.qwen2_5_3b() }, // Qwen3.5 - { label: 'Qwen3.5 0.8B Quantized', value: models.llm.qwen3_5_0_8b() }, - { label: 'Qwen3.5 2B Quantized', value: models.llm.qwen3_5_2b() }, + { label: 'Qwen3.5 0.8B Quantized', value: llm.qwen3_5_0_8b() }, + { label: 'Qwen3.5 2B Quantized', value: llm.qwen3_5_2b() }, // Phi-4 { label: 'Phi-4 Mini 4B', - value: models.llm.phi_4_mini_4b({ quant: false }), + value: llm.phi_4_mini_4b({ quant: false }), }, { label: 'Phi-4 Mini 4B Quantized', - value: models.llm.phi_4_mini_4b(), + value: llm.phi_4_mini_4b(), }, // LFM2.5 { label: 'LFM2.5 350M', - value: models.llm.lfm2_5_350m({ quant: false }), + value: llm.lfm2_5_350m({ quant: false }), }, - { label: 'LFM2.5 350M Quantized', value: models.llm.lfm2_5_350m() }, + { label: 'LFM2.5 350M Quantized', value: llm.lfm2_5_350m() }, { label: 'LFM2.5 1.2B Instruct', - value: models.llm.lfm2_5_1_2b_instruct({ quant: false }), + value: llm.lfm2_5_1_2b_instruct({ quant: false }), }, { label: 'LFM2.5 1.2B Instruct Quantized', - value: models.llm.lfm2_5_1_2b_instruct(), + value: llm.lfm2_5_1_2b_instruct(), }, // Bielik v3.0 { label: 'Bielik v3.0 1.5B', - value: models.llm.bielik_v3_0_1_5b({ quant: false }), + value: llm.bielik_v3_0_1_5b({ quant: false }), }, { label: 'Bielik v3.0 1.5B Quantized', - value: models.llm.bielik_v3_0_1_5b(), + value: llm.bielik_v3_0_1_5b(), }, ]; diff --git a/apps/speech/screens/SpeechToTextScreen.tsx b/apps/speech/screens/SpeechToTextScreen.tsx index d5b78edbc9..532ccfd59e 100644 --- a/apps/speech/screens/SpeechToTextScreen.tsx +++ b/apps/speech/screens/SpeechToTextScreen.tsx @@ -18,25 +18,26 @@ import { SpeechToTextProps, } from 'react-native-executorch'; import { ModelPicker, ModelOption } from '../components/ModelPicker'; +const speechToText = models.speech_to_text; type STTModelSources = SpeechToTextProps['model']; const MODELS: ModelOption[] = [ { label: 'Whisper Tiny', - value: models.speech_to_text.whisper_tiny_en({ quant: false }), + value: speechToText.whisper_tiny_en({ quant: false }), }, { label: 'Whisper Tiny Q', - value: models.speech_to_text.whisper_tiny_en(), + value: speechToText.whisper_tiny_en(), }, { label: 'Whisper Base', - value: models.speech_to_text.whisper_base_en(), + value: speechToText.whisper_base_en(), }, { label: 'Whisper Small', - value: models.speech_to_text.whisper_small_en(), + value: speechToText.whisper_small_en(), }, ]; import FontAwesome from '@expo/vector-icons/FontAwesome'; @@ -56,7 +57,7 @@ const isSimulator = DeviceInfo.isEmulatorSync(); export const SpeechToTextScreen = ({ onBack }: { onBack: () => void }) => { const [selectedModel, setSelectedModel] = useState( - models.speech_to_text.whisper_tiny_en({ quant: false }) + speechToText.whisper_tiny_en({ quant: false }) ); const model = useSpeechToText({ diff --git a/apps/text-embeddings/app/text-embeddings/index.tsx b/apps/text-embeddings/app/text-embeddings/index.tsx index fe1514bd9b..5120688edb 100644 --- a/apps/text-embeddings/app/text-embeddings/index.tsx +++ b/apps/text-embeddings/app/text-embeddings/index.tsx @@ -17,38 +17,39 @@ import { useTextEmbeddings, TextEmbeddingsProps, } from 'react-native-executorch'; +const textEmbedding = models.text_embedding; type TextEmbeddingModel = TextEmbeddingsProps['model']; const MODELS: { label: string; value: TextEmbeddingModel }[] = [ - { label: 'MiniLM L6', value: models.text_embedding.all_minilm_l6_v2() }, + { label: 'MiniLM L6', value: textEmbedding.all_minilm_l6_v2() }, { label: 'MPNet Base', - value: models.text_embedding.all_mpnet_base_v2(), + value: textEmbedding.all_mpnet_base_v2(), }, { label: 'MultiQA MiniLM', - value: models.text_embedding.multi_qa_minilm_l6_cos_v1(), + value: textEmbedding.multi_qa_minilm_l6_cos_v1(), }, { label: 'MultiQA MPNet', - value: models.text_embedding.multi_qa_mpnet_base_dot_v1(), + value: textEmbedding.multi_qa_mpnet_base_dot_v1(), }, { label: 'Multilingual DistilUSE (xnnpack)', - value: models.text_embedding.distiluse_base_multilingual_cased_v2({ + value: textEmbedding.distiluse_base_multilingual_cased_v2({ backend: 'xnnpack', }), }, { label: 'Multilingual DistilUSE (CoreML)', - value: models.text_embedding.distiluse_base_multilingual_cased_v2({ + value: textEmbedding.distiluse_base_multilingual_cased_v2({ backend: 'coreml', }), }, { label: 'Multilingual Paraphrase (8da4w)', - value: models.text_embedding.paraphrase_multilingual_minilm_l12_v2(), + value: textEmbedding.paraphrase_multilingual_minilm_l12_v2(), }, ]; import { useIsFocused } from '@react-navigation/native'; @@ -63,7 +64,7 @@ export default function TextEmbeddingsScreenWrapper() { function TextEmbeddingsScreen() { const [selectedModel, setSelectedModel] = useState( - models.text_embedding.all_minilm_l6_v2() + textEmbedding.all_minilm_l6_v2() ); const model = useTextEmbeddings({ model: selectedModel }); const [error, setError] = useState(null); From 18810c44cb7f0cd6518c9496ef4283db08d3b851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Mon, 18 May 2026 18:26:37 +0200 Subject: [PATCH 14/16] fix(docs): repoint v0.8.x model-registry link from /next/ to its own version The 0.8.x doc linked at \`/docs/next/api-reference/variables/MODEL_REGISTRY\`, which broke once the next-version docs renamed the variable to \`models\`. Use a relative path within the 0.8.x version so the link is independent of later renames. --- .../versioned_docs/version-0.8.x/05-utilities/model-registry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/versioned_docs/version-0.8.x/05-utilities/model-registry.md b/docs/versioned_docs/version-0.8.x/05-utilities/model-registry.md index 3b4241c986..7c15dc1205 100644 --- a/docs/versioned_docs/version-0.8.x/05-utilities/model-registry.md +++ b/docs/versioned_docs/version-0.8.x/05-utilities/model-registry.md @@ -2,7 +2,7 @@ title: Model Registry --- -The [Model Registry](/react-native-executorch/docs/next/api-reference/variables/MODEL_REGISTRY) is a collection of all pre-configured model definitions shipped with React Native ExecuTorch. Each entry contains the model's name and all source URLs needed to download and run it, so you don't have to manage URLs manually. +The [Model Registry](../api-reference/variables/MODEL_REGISTRY) is a collection of all pre-configured model definitions shipped with React Native ExecuTorch. Each entry contains the model's name and all source URLs needed to download and run it, so you don't have to manage URLs manually. ## Usage From 698ed7f4e1713ede15850dd7d713ee3da1c7f600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Tue, 19 May 2026 12:43:16 +0200 Subject: [PATCH 15/16] =?UTF-8?q?refactor(registry)!:=20rename=20`multimod?= =?UTF-8?q?al`=E2=86=92`lmm`;=20split=20`privacy=5Ffilter`,=20add=20`pose?= =?UTF-8?q?=5Festimation`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `models.multimodal` is renamed to `models.lmm` (Large Multimodal Models) — clearer than the generic "multimodal" tag now that LMMs span audio+vision. - `privacy_filter_*` is moved out of `models.classification` into its own `models.privacy_filter` group (it has a dedicated hook and a distinct model-name union, so grouping under `classification` was misleading). - Pose estimation is added as `models.pose_estimation` (`yolo26n`). Example apps that select these models are updated. --- .../app/pose_estimation/index.tsx | 4 ++-- .../vision_camera/tasks/PoseEstimationTask.tsx | 4 ++-- apps/llm/app/multimodal_llm/index.tsx | 2 +- apps/llm/app/privacy_filter/index.tsx | 16 ++++++++++------ .../src/constants/modelRegistry.ts | 11 ++++++++--- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/apps/computer-vision/app/pose_estimation/index.tsx b/apps/computer-vision/app/pose_estimation/index.tsx index 3a07816e7e..4546b628fa 100644 --- a/apps/computer-vision/app/pose_estimation/index.tsx +++ b/apps/computer-vision/app/pose_estimation/index.tsx @@ -2,11 +2,11 @@ import Spinner from '../../components/Spinner'; import { BottomBar } from '../../components/BottomBar'; import { getImage } from '../../utils'; import { + models, usePoseEstimation, PoseDetections, RnExecutorchError, RnExecutorchErrorCode, - YOLO26N_POSE, } from 'react-native-executorch'; import { View, StyleSheet, Image, Text } from 'react-native'; import React, { useContext, useEffect, useState } from 'react'; @@ -31,7 +31,7 @@ export default function PoseEstimationScreen() { const [inferenceTime, setInferenceTime] = useState(null); const [layout, setLayout] = useState({ width: 0, height: 0 }); - const model = usePoseEstimation({ model: YOLO26N_POSE }); + const model = usePoseEstimation({ model: models.pose_estimation.yolo26n() }); const { setGlobalGenerating } = useContext(GeneratingContext); useEffect(() => { diff --git a/apps/computer-vision/components/vision_camera/tasks/PoseEstimationTask.tsx b/apps/computer-vision/components/vision_camera/tasks/PoseEstimationTask.tsx index 476435643d..a357881da0 100644 --- a/apps/computer-vision/components/vision_camera/tasks/PoseEstimationTask.tsx +++ b/apps/computer-vision/components/vision_camera/tasks/PoseEstimationTask.tsx @@ -4,9 +4,9 @@ import { Frame, useFrameOutput } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; import Svg, { Circle, Line } from 'react-native-svg'; import { + models, usePoseEstimation, PoseDetections, - YOLO26N_POSE, } from 'react-native-executorch'; import { TaskProps } from './types'; import { COCO_SKELETON_CONNECTIONS } from '../../utils/cocoSkeleton'; @@ -29,7 +29,7 @@ export default function PoseEstimationTask({ onErrorChange, }: Props) { const poseModel = usePoseEstimation({ - model: YOLO26N_POSE, + model: models.pose_estimation.yolo26n(), preventLoad: activeModel !== 'poseEstimationYolo26n', }); diff --git a/apps/llm/app/multimodal_llm/index.tsx b/apps/llm/app/multimodal_llm/index.tsx index 408798e967..8443d2d770 100644 --- a/apps/llm/app/multimodal_llm/index.tsx +++ b/apps/llm/app/multimodal_llm/index.tsx @@ -50,7 +50,7 @@ function MultimodalLLMScreen() { const [error, setError] = useState(null); const vlm = useLLM({ - model: models.multimodal.lfm2_5_vl_1_6b(), + model: models.lmm.lfm2_5_vl_1_6b(), }); const tokenCount = vlm.isReady ? vlm.getGeneratedTokenCount() : 0; const { stats, onMessageSend } = useLLMStats( diff --git a/apps/llm/app/privacy_filter/index.tsx b/apps/llm/app/privacy_filter/index.tsx index e6541dfe52..6f3e132bc1 100644 --- a/apps/llm/app/privacy_filter/index.tsx +++ b/apps/llm/app/privacy_filter/index.tsx @@ -10,12 +10,13 @@ import { import { useIsFocused } from '@react-navigation/native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { + models, PiiEntity, - PRIVACY_FILTER_NEMOTRON, - PRIVACY_FILTER_OPENAI, PrivacyFilterModelSources, usePrivacyFilter, } from 'react-native-executorch'; + +const privacyFilter = models.privacy_filter; import ColorPalette from '../../colors'; import { ModelOption, ModelPicker } from '../../components/ModelPicker'; import { @@ -46,16 +47,19 @@ Workstation MAC 3C:22:FB:8E:01:9A, IPv4 10.0.42.118, device IMEI 359888061234560 /* cspell:enable */ const MODEL_OPTIONS: ModelOption[] = [ - { label: 'OpenAI Privacy Filter (8 entities)', value: PRIVACY_FILTER_OPENAI }, + { + label: 'OpenAI Privacy Filter (8 entities)', + value: privacyFilter.openai(), + }, { label: 'OpenMed Nemotron (55 entities)', - value: PRIVACY_FILTER_NEMOTRON, + value: privacyFilter.nemotron(), }, ]; // Pick the right sample to display/run based on the active model. function sampleFor(model: PrivacyFilterModelSources): string { - return model.modelName === PRIVACY_FILTER_NEMOTRON.modelName + return model.modelName === privacyFilter.nemotron().modelName ? NEMOTRON_SAMPLE : OPENAI_SAMPLE; } @@ -98,7 +102,7 @@ function PrivacyFilterScreen() { const [runError, setRunError] = useState(null); const [inferenceMs, setInferenceMs] = useState(null); const [selectedModel, setSelectedModel] = useState( - PRIVACY_FILTER_OPENAI + privacyFilter.openai() ); const filter = usePrivacyFilter({ model: selectedModel }); diff --git a/packages/react-native-executorch/src/constants/modelRegistry.ts b/packages/react-native-executorch/src/constants/modelRegistry.ts index 1215e96b03..309c4bd720 100644 --- a/packages/react-native-executorch/src/constants/modelRegistry.ts +++ b/packages/react-native-executorch/src/constants/modelRegistry.ts @@ -399,14 +399,16 @@ export const models = { ), bielik_v3_0_1_5b: pair(M.BIELIK_V3_0_1_5B, M.BIELIK_V3_0_1_5B_QUANTIZED), }, - multimodal: { + lmm: { lfm2_5_vl_1_6b: base(M.LFM2_5_VL_1_6B_QUANTIZED), lfm2_5_vl_450m: base(M.LFM2_5_VL_450M_QUANTIZED), }, classification: { efficientnet_v2_s: variant(EFFICIENTNET_V2_S_VARIANTS, COREML_ON_IOS), - privacy_filter_openai: base(M.PRIVACY_FILTER_OPENAI), - privacy_filter_nemotron: base(M.PRIVACY_FILTER_NEMOTRON), + }, + privacy_filter: { + openai: base(M.PRIVACY_FILTER_OPENAI), + nemotron: base(M.PRIVACY_FILTER_NEMOTRON), }, object_detection: { ssdlite_320_mobilenet_v3_large: variant( @@ -422,6 +424,9 @@ export const models = { fastsam_s: variant(FASTSAM_S_VARIANTS, COREML_ON_IOS), fastsam_x: variant(FASTSAM_X_VARIANTS, COREML_ON_IOS), }, + pose_estimation: { + yolo26n: base(M.YOLO26N_POSE), + }, semantic_segmentation: { deeplab_v3_resnet50: pair( M.DEEPLAB_V3_RESNET50, From bb81ac33eb8400e6b4e7c51e3d1a38b81dfc48a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Tue, 19 May 2026 12:43:42 +0200 Subject: [PATCH 16/16] docs: migrate model-selection snippets to the `models` accessor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every code snippet that selected a model via a named constant (`LFM2_5_1_2B_INSTRUCT`, `OCR_ENGLISH`, `KOKORO_MEDIUM`, …) is rewritten to use the typed `models..()` accessor. Snippets default to the quantized variant where one is published — the constant-import path still works and is documented in the Model Registry guide. webrtc-integration intentionally keeps the named-constant style: the snippet sits next to imports from other libraries and the bare constant reads cleaner in that context. --- .../docs/01-fundamentals/02-loading-models.md | 5 +-- .../01-natural-language-processing/useLLM.md | 29 ++++++------- .../usePrivacyFilter.md | 17 ++------ .../useSpeechToText.md | 17 ++++---- .../useTextEmbeddings.md | 14 +++--- .../useTextToSpeech.md | 41 ++++++------------ .../useTokenizer.md | 14 +++--- .../01-natural-language-processing/useVAD.md | 8 ++-- .../02-computer-vision/useClassification.md | 14 +++--- .../02-computer-vision/useImageEmbeddings.md | 10 ++--- .../useInstanceSegmentation.md | 17 ++++---- .../03-hooks/02-computer-vision/useOCR.md | 10 ++--- .../02-computer-vision/useObjectDetection.md | 13 ++---- .../02-computer-vision/usePoseEstimation.md | 10 ++--- .../useSemanticSegmentation.md | 13 ++---- .../02-computer-vision/useStyleTransfer.md | 16 ++----- .../02-computer-vision/useTextToImage.md | 14 +++--- .../02-computer-vision/useVerticalOCR.md | 10 ++--- .../visioncamera-integration.md | 21 ++++----- .../useExecutorchModule.md | 6 +-- .../LLMModule.md | 13 +++--- .../PrivacyFilterModule.md | 8 +--- .../SpeechToTextModule.md | 18 ++++---- .../TextEmbeddingsModule.md | 11 ++--- .../TextToSpeechModule.md | 43 ++++++------------- .../TokenizerModule.md | 5 +-- .../VADModule.md | 5 +-- .../ClassificationModule.md | 12 ++---- .../ImageEmbeddingsModule.md | 8 +--- .../InstanceSegmentationModule.md | 22 ++++------ .../02-computer-vision/OCRModule.md | 4 +- .../ObjectDetectionModule.md | 9 +--- .../PoseEstimationModule.md | 9 ++-- .../SemanticSegmentationModule.md | 13 +++--- .../02-computer-vision/StyleTransferModule.md | 11 ++--- .../02-computer-vision/TextToImageModule.md | 8 +--- .../02-computer-vision/VerticalOCRModule.md | 7 +-- .../ExecutorchModule.md | 18 ++------ docs/docs/05-utilities/04-error-handling.md | 5 +-- docs/docs/05-utilities/model-registry.md | 6 ++- .../08-resource-fetcher/02-custom-adapter.md | 1 - 41 files changed, 205 insertions(+), 330 deletions(-) diff --git a/docs/docs/01-fundamentals/02-loading-models.md b/docs/docs/01-fundamentals/02-loading-models.md index 3a3eaab722..ffadd5dc08 100644 --- a/docs/docs/01-fundamentals/02-loading-models.md +++ b/docs/docs/01-fundamentals/02-loading-models.md @@ -87,7 +87,6 @@ Our library offers out-of-the-box support for multiple models. To make things ea The following code snippet demonstrates how to load model and tokenizer files using `useLLM` hook: ```typescript -import { useLLM, LFM2_5_1_2B_INSTRUCT } from 'react-native-executorch'; - -const llm = useLLM({ model: LFM2_5_1_2B_INSTRUCT }); +import { models, useLLM } from 'react-native-executorch'; +const llm = useLLM({ model: models.llm.lfm2_5_1_2b_instruct() }); ``` diff --git a/docs/docs/03-hooks/01-natural-language-processing/useLLM.md b/docs/docs/03-hooks/01-natural-language-processing/useLLM.md index 7e6e4b17c2..0b330c6b12 100644 --- a/docs/docs/03-hooks/01-natural-language-processing/useLLM.md +++ b/docs/docs/03-hooks/01-natural-language-processing/useLLM.md @@ -44,9 +44,8 @@ Lower-end devices might not be able to fit LLMs into memory. We recommend using In order to load a model into the app, you need to run the following code: ```typescript -import { useLLM, LFM2_5_1_2B_INSTRUCT } from 'react-native-executorch'; - -const llm = useLLM({ model: LFM2_5_1_2B_INSTRUCT }); +import { models, useLLM } from 'react-native-executorch'; +const llm = useLLM({ model: models.llm.lfm2_5_1_2b_instruct() }); ```
@@ -92,7 +91,7 @@ You can use functions returned from this hooks in two manners: To perform chat completion you can use the [`generate`](../../06-api-reference/interfaces/LLMType.md#generate) function. The [`response`](../../06-api-reference/interfaces/LLMType.md#response) value is updated with each token as it's generated, and the function returns a promise that resolves to the complete response when generation finishes. ```tsx -const llm = useLLM({ model: LFM2_5_1_2B_INSTRUCT }); +const llm = useLLM({ model: models.llm.lfm2_5_1_2b_instruct() }); const handleGenerate = async () => { const chat: Message[] = [ @@ -152,7 +151,7 @@ const TOOL_DEFINITIONS: LLMTool[] = [ }, ]; -const llm = useLLM({ model: HAMMER2_1_1_5B }); +const llm = useLLM({ model: models.llm.hammer2_1_1_5b() }); const handleGenerate = () => { const chat: Message[] = [ @@ -226,13 +225,12 @@ Model presets expose an optional [`generationConfig`](../../06-api-reference/int ```tsx import { useEffect } from 'react'; import { + models, MessageCountContextStrategy, DEFAULT_SYSTEM_PROMPT, ToolCall, useLLM, - LFM2_5_1_2B_INSTRUCT, } from 'react-native-executorch'; - const TOOL_DEFINITIONS: LLMTool[] = [ { name: 'get_weather', @@ -266,7 +264,7 @@ const executeTool: (call: ToolCall) => Promise = async ( } }; -const llm = useLLM({ model: LFM2_5_1_2B_INSTRUCT }); +const llm = useLLM({ model: models.llm.lfm2_5_1_2b_instruct() }); const { configure } = llm; useEffect(() => { @@ -303,7 +301,7 @@ useEffect(() => { In order to send a message to the model, one can use the following code: ```tsx -const llm = useLLM({ model: LFM2_5_1_2B_INSTRUCT }); +const llm = useLLM({ model: models.llm.lfm2_5_1_2b_instruct() }); const send = () => { const message = 'Hi, who are you?'; @@ -348,7 +346,7 @@ const TOOL_DEFINITIONS: LLMTool[] = [ }, ]; -const llm = useLLM({ model: HAMMER2_1_1_5B }); +const llm = useLLM({ model: models.llm.hammer2_1_1_5b() }); useEffect(() => { llm.configure({ @@ -426,7 +424,7 @@ const responseSchemaWithZod = z.object({ currency: z.optional(z.string().meta({ description: 'Currency of offer.' })), }); -const llm = useLLM({ model: QWEN3_4B_QUANTIZED }); +const llm = useLLM({ model: models.llm.qwen3_4b() }); useEffect(() => { const formattingInstructions = getStructuredOutputPrompt(responseSchema); @@ -501,9 +499,8 @@ Some models support multimodal input — text and images together. To use them, ### Loading a VLM ```tsx -import { useLLM, LFM2_5_VL_1_6B_QUANTIZED } from 'react-native-executorch'; - -const llm = useLLM({ model: LFM2_5_VL_1_6B_QUANTIZED }); +import { models, useLLM } from 'react-native-executorch'; +const llm = useLLM({ model: models.lmm.lfm2_5_vl_1_6b() }); ``` The `capabilities` field is already set on the model constant. You can also construct the model object explicitly: @@ -524,7 +521,7 @@ Passing `capabilities` unlocks the typed `media` argument on `sendMessage`. ### Sending a message with an image ```tsx -const llm = useLLM({ model: LFM2_5_VL_1_6B_QUANTIZED }); +const llm = useLLM({ model: models.lmm.lfm2_5_vl_1_6b() }); const send = () => { llm.sendMessage('What is in this image?', { @@ -547,7 +544,7 @@ The `imagePath` should be a local file path on the device. You can also use `generate` directly by setting `mediaPath` on user messages: ```tsx -const llm = useLLM({ model: LFM2_5_VL_1_6B_QUANTIZED }); +const llm = useLLM({ model: models.lmm.lfm2_5_vl_1_6b() }); const handleGenerate = async () => { const chat: Message[] = [ diff --git a/docs/docs/03-hooks/01-natural-language-processing/usePrivacyFilter.md b/docs/docs/03-hooks/01-natural-language-processing/usePrivacyFilter.md index c0155dfbbf..97495f510b 100644 --- a/docs/docs/03-hooks/01-natural-language-processing/usePrivacyFilter.md +++ b/docs/docs/03-hooks/01-natural-language-processing/usePrivacyFilter.md @@ -32,12 +32,8 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```typescript -import { - usePrivacyFilter, - PRIVACY_FILTER_OPENAI, -} from 'react-native-executorch'; - -const model = usePrivacyFilter({ model: PRIVACY_FILTER_OPENAI }); +import { models, usePrivacyFilter } from 'react-native-executorch'; +const model = usePrivacyFilter({ model: models.privacy_filter.openai() }); try { const entities = await model.generate( @@ -89,14 +85,9 @@ Both built-in models ship with neutral, validity-only Viterbi decoding by defaul ```tsx import React, { useState } from 'react'; import { Button, Text, View, TextInput, ScrollView } from 'react-native'; -import { - usePrivacyFilter, - PRIVACY_FILTER_OPENAI, - PiiEntity, -} from 'react-native-executorch'; - +import { models, usePrivacyFilter, PiiEntity } from 'react-native-executorch'; export default function App() { - const model = usePrivacyFilter({ model: PRIVACY_FILTER_OPENAI }); + const model = usePrivacyFilter({ model: models.privacy_filter.openai() }); const [text, setText] = useState( 'My name is Sarah Chen and you can reach me at sarah.chen@example.com.' ); diff --git a/docs/docs/03-hooks/01-natural-language-processing/useSpeechToText.md b/docs/docs/03-hooks/01-natural-language-processing/useSpeechToText.md index 089b844eb0..39d0566af5 100644 --- a/docs/docs/03-hooks/01-natural-language-processing/useSpeechToText.md +++ b/docs/docs/03-hooks/01-natural-language-processing/useSpeechToText.md @@ -33,12 +33,12 @@ It is recommended to use models provided by us, which are available at our [Hugg You can obtain waveform from audio in any way most suitable to you, however in the snippet below we utilize [`react-native-audio-api`](https://docs.swmansion.com/react-native-audio-api/) library to process a `.mp3` file. ```typescript -import { useSpeechToText, WHISPER_TINY_EN } from 'react-native-executorch'; +import { models, useSpeechToText } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; import * as FileSystem from 'expo-file-system'; const model = useSpeechToText({ - model: WHISPER_TINY_EN, + model: models.speech_to_text.whisper_tiny_en(), }); const { uri } = await FileSystem.downloadAsync( @@ -92,10 +92,9 @@ Before running the model's [`transcribe`](../../06-api-reference/interfaces/Spee If you want to transcribe speech in languages other than English, use the multilingual version of Whisper. To generate the output in your desired language, pass the [`language`](../../06-api-reference/interfaces/DecodingOptions.md#language) option to the [`transcribe`](../../06-api-reference/interfaces/SpeechToTextType.md#transcribe) method. ```typescript -import { useSpeechToText, WHISPER_TINY } from 'react-native-executorch'; - +import { models, useSpeechToText } from 'react-native-executorch'; const model = useSpeechToText({ - model: WHISPER_TINY, + model: models.speech_to_text.whisper_tiny(), }); const transcription = await model.transcribe(spanishAudio, { language: 'es' }); @@ -143,8 +142,8 @@ const transcription = await model.transcribe(audioBuffer, { verbose: true }); import React, { useState } from 'react'; import { Button, Text, View } from 'react-native'; import { + models, useSpeechToText, - WHISPER_TINY_EN, TranscriptionResult, } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; @@ -152,7 +151,7 @@ import * as FileSystem from 'expo-file-system'; function App() { const model = useSpeechToText({ - model: WHISPER_TINY_EN, + model: models.speech_to_text.whisper_tiny_en(), }); const [transcription, setTranscription] = useState(null); @@ -220,12 +219,12 @@ function App() { ```tsx import React, { useEffect, useState, useRef } from 'react'; import { Text, Button, View, SafeAreaView } from 'react-native'; -import { useSpeechToText, WHISPER_TINY_EN } from 'react-native-executorch'; +import { models, useSpeechToText } from 'react-native-executorch'; import { AudioManager, AudioRecorder } from 'react-native-audio-api'; export default function App() { const model = useSpeechToText({ - model: WHISPER_TINY_EN, + model: models.speech_to_text.whisper_tiny_en(), }); const [transcribedText, setTranscribedText] = useState(''); diff --git a/docs/docs/03-hooks/01-natural-language-processing/useTextEmbeddings.md b/docs/docs/03-hooks/01-natural-language-processing/useTextEmbeddings.md index 09240d1e75..b9ba8c41b9 100644 --- a/docs/docs/03-hooks/01-natural-language-processing/useTextEmbeddings.md +++ b/docs/docs/03-hooks/01-natural-language-processing/useTextEmbeddings.md @@ -29,9 +29,10 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```typescript -import { useTextEmbeddings, ALL_MINILM_L6_V2 } from 'react-native-executorch'; - -const model = useTextEmbeddings({ model: ALL_MINILM_L6_V2 }); +import { models, useTextEmbeddings } from 'react-native-executorch'; +const model = useTextEmbeddings({ + model: models.text_embedding.all_minilm_l6_v2(), +}); try { const embedding = await model.forward('Hello World!'); @@ -64,8 +65,7 @@ To run the model, you can use the [`forward`](../../06-api-reference/interfaces/ ## Example ```typescript -import { useTextEmbeddings, ALL_MINILM_L6_V2 } from 'react-native-executorch'; - +import { models, useTextEmbeddings } from 'react-native-executorch'; const dotProduct = (a: number[], b: number[]) => a.reduce((sum, val, i) => sum + val * b[i], 0); @@ -77,7 +77,9 @@ const cosineSimilarity = (a: number[], b: number[]) => { }; function App() { - const model = useTextEmbeddings({ model: ALL_MINILM_L6_V2 }); + const model = useTextEmbeddings({ + model: models.text_embedding.all_minilm_l6_v2(), + }); // ... diff --git a/docs/docs/03-hooks/01-natural-language-processing/useTextToSpeech.md b/docs/docs/03-hooks/01-natural-language-processing/useTextToSpeech.md index 184dd1f116..95299a7f19 100644 --- a/docs/docs/03-hooks/01-natural-language-processing/useTextToSpeech.md +++ b/docs/docs/03-hooks/01-natural-language-processing/useTextToSpeech.md @@ -33,16 +33,12 @@ It is recommended to use models provided by us, which are available at our [Hugg You can play the generated waveform in any way most suitable to you; however, in the snippet below we utilize the react-native-audio-api library to play synthesized speech. ```typescript -import { - useTextToSpeech, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; +import { models, useTextToSpeech } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; const model = useTextToSpeech({ - model: KOKORO_MEDIUM, - voice: KOKORO_VOICE_AF_HEART, + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, }); const audioContext = new AudioContext({ sampleRate: 24000 }); @@ -108,17 +104,13 @@ Since `forward` and `forwardFromPhonemes` process the entire input at once, they ```tsx import React from 'react'; import { Button, View } from 'react-native'; -import { - useTextToSpeech, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; +import { models, useTextToSpeech } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; export default function App() { const tts = useTextToSpeech({ - model: KOKORO_MEDIUM, - voice: KOKORO_VOICE_AF_HEART, + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, }); const generateAudio = async () => { @@ -150,17 +142,13 @@ export default function App() { ```tsx import React, { useRef } from 'react'; import { Button, View } from 'react-native'; -import { - useTextToSpeech, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; +import { models, useTextToSpeech } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; export default function App() { const tts = useTextToSpeech({ - model: KOKORO_MEDIUM, - voice: KOKORO_VOICE_AF_HEART, + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, }); const contextRef = useRef(new AudioContext({ sampleRate: 24000 })); @@ -201,16 +189,11 @@ If you already have a phoneme string obtained from an external source (e.g. the ```tsx import React from 'react'; import { Button, View } from 'react-native'; -import { - useTextToSpeech, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; - +import { models, useTextToSpeech } from 'react-native-executorch'; export default function App() { const tts = useTextToSpeech({ - model: KOKORO_MEDIUM, - voice: KOKORO_VOICE_AF_HEART, + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, }); const synthesizePhonemes = async () => { diff --git a/docs/docs/03-hooks/01-natural-language-processing/useTokenizer.md b/docs/docs/03-hooks/01-natural-language-processing/useTokenizer.md index 42ef8b0685..fed10291ba 100644 --- a/docs/docs/03-hooks/01-natural-language-processing/useTokenizer.md +++ b/docs/docs/03-hooks/01-natural-language-processing/useTokenizer.md @@ -29,9 +29,10 @@ We are using [Hugging Face Tokenizers](https://huggingface.co/docs/tokenizers/in ## High Level Overview ```typescript -import { useTokenizer, ALL_MINILM_L6_V2 } from 'react-native-executorch'; - -const tokenizer = useTokenizer({ tokenizer: ALL_MINILM_L6_V2 }); +import { models, useTokenizer } from 'react-native-executorch'; +const tokenizer = useTokenizer({ + tokenizer: models.text_embedding.all_minilm_l6_v2(), +}); const text = 'Hello, world!'; @@ -67,10 +68,11 @@ You need more details? Check the following resources: ## Example ```typescript -import { useTokenizer, ALL_MINILM_L6_V2 } from 'react-native-executorch'; - +import { models, useTokenizer } from 'react-native-executorch'; function App() { - const tokenizer = useTokenizer({ tokenizer: ALL_MINILM_L6_V2 }); + const tokenizer = useTokenizer({ + tokenizer: models.text_embedding.all_minilm_l6_v2(), + }); // ... diff --git a/docs/docs/03-hooks/01-natural-language-processing/useVAD.md b/docs/docs/03-hooks/01-natural-language-processing/useVAD.md index 81207dec07..01cf8cd4e3 100644 --- a/docs/docs/03-hooks/01-natural-language-processing/useVAD.md +++ b/docs/docs/03-hooks/01-natural-language-processing/useVAD.md @@ -18,12 +18,12 @@ It is recommended to use models provided by us, which are available at our [Hugg You can obtain waveform from audio in any way most suitable to you, however in the snippet below we utilize [`react-native-audio-api`](https://docs.swmansion.com/react-native-audio-api/) library to process a `.mp3` file. ```typescript -import { useVAD, FSMN_VAD } from 'react-native-executorch'; +import { models, useVAD } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; import * as FileSystem from 'expo-file-system'; const model = useVAD({ - model: FSMN_VAD, + model: models.vad.fsmn_vad(), }); const { uri } = await FileSystem.downloadAsync( @@ -76,13 +76,13 @@ Timestamps in returned speech segments, correspond to indices of input array (wa ```tsx import React from 'react'; import { Button, Text, SafeAreaView } from 'react-native'; -import { useVAD, FSMN_VAD } from 'react-native-executorch'; +import { models, useVAD } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; import * as FileSystem from 'expo-file-system'; export default function App() { const model = useVAD({ - model: FSMN_VAD, + model: models.vad.fsmn_vad(), }); const audioURL = 'https://some-audio-url.com/file.mp3'; diff --git a/docs/docs/03-hooks/02-computer-vision/useClassification.md b/docs/docs/03-hooks/02-computer-vision/useClassification.md index 53ec0901bd..7db709dd9a 100644 --- a/docs/docs/03-hooks/02-computer-vision/useClassification.md +++ b/docs/docs/03-hooks/02-computer-vision/useClassification.md @@ -20,9 +20,10 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```typescript -import { useClassification, EFFICIENTNET_V2_S } from 'react-native-executorch'; - -const model = useClassification({ model: EFFICIENTNET_V2_S }); +import { models, useClassification } from 'react-native-executorch'; +const model = useClassification({ + model: models.classification.efficientnet_v2_s(), +}); const imageUri = 'file::///Users/.../cute_puppy.png'; @@ -75,10 +76,11 @@ See the full guide: [VisionCamera Integration](./visioncamera-integration.md). ## Example ```typescript -import { useClassification, EFFICIENTNET_V2_S } from 'react-native-executorch'; - +import { models, useClassification } from 'react-native-executorch'; function App() { - const model = useClassification({ model: EFFICIENTNET_V2_S }); + const model = useClassification({ + model: models.classification.efficientnet_v2_s(), + }); // ... const imageUri = 'file:///Users/.../cute_puppy.png'; diff --git a/docs/docs/03-hooks/02-computer-vision/useImageEmbeddings.md b/docs/docs/03-hooks/02-computer-vision/useImageEmbeddings.md index df2442c6bd..13947a96f2 100644 --- a/docs/docs/03-hooks/02-computer-vision/useImageEmbeddings.md +++ b/docs/docs/03-hooks/02-computer-vision/useImageEmbeddings.md @@ -30,12 +30,10 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```typescript -import { - useImageEmbeddings, - CLIP_VIT_BASE_PATCH32_IMAGE, -} from 'react-native-executorch'; - -const model = useImageEmbeddings({ model: CLIP_VIT_BASE_PATCH32_IMAGE }); +import { models, useImageEmbeddings } from 'react-native-executorch'; +const model = useImageEmbeddings({ + model: models.image_embedding.clip_vit_base_patch32_image(), +}); try { const imageEmbedding = await model.forward('https://url-to-image.jpg'); diff --git a/docs/docs/03-hooks/02-computer-vision/useInstanceSegmentation.md b/docs/docs/03-hooks/02-computer-vision/useInstanceSegmentation.md index 6835262a6a..d1728a3cf8 100644 --- a/docs/docs/03-hooks/02-computer-vision/useInstanceSegmentation.md +++ b/docs/docs/03-hooks/02-computer-vision/useInstanceSegmentation.md @@ -15,10 +15,9 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```typescript -import { useInstanceSegmentation, YOLO26N_SEG } from 'react-native-executorch'; - +import { models, useInstanceSegmentation } from 'react-native-executorch'; const model = useInstanceSegmentation({ - model: YOLO26N_SEG, + model: models.instance_segmentation.yolo26n_seg(), }); const imageUri = 'file:///Users/.../photo.jpg'; @@ -81,11 +80,10 @@ To run the model, use the [`forward`](../../06-api-reference/interfaces/Instance ## Example ```typescript -import { useInstanceSegmentation, YOLO26N_SEG } from 'react-native-executorch'; - +import { models, useInstanceSegmentation } from 'react-native-executorch'; function App() { const model = useInstanceSegmentation({ - model: YOLO26N_SEG, + model: models.instance_segmentation.yolo26n_seg(), }); const handleSegment = async () => { @@ -150,14 +148,15 @@ Instance segmentation models return a list of segmented instances. After `forwar ```typescript import { + models, useInstanceSegmentation, selectByPoint, selectByBox, selectByText, - FASTSAM_X, } from 'react-native-executorch'; - -const model = useInstanceSegmentation({ model: FASTSAM_X }); +const model = useInstanceSegmentation({ + model: models.object_detection.fastsam_x(), +}); try { const instances = await model.forward(imageUri); diff --git a/docs/docs/03-hooks/02-computer-vision/useOCR.md b/docs/docs/03-hooks/02-computer-vision/useOCR.md index 8f015e77a5..e23b5a7934 100644 --- a/docs/docs/03-hooks/02-computer-vision/useOCR.md +++ b/docs/docs/03-hooks/02-computer-vision/useOCR.md @@ -16,10 +16,9 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```tsx -import { useOCR, OCR_ENGLISH } from 'react-native-executorch'; - +import { models, useOCR } from 'react-native-executorch'; function App() { - const model = useOCR({ model: OCR_ENGLISH }); + const model = useOCR({ model: models.ocr({ language: 'en' }) }); // ... for (const ocrDetection of await model.forward('https://url-to-image.jpg')) { @@ -81,10 +80,9 @@ The `text` property contains the text recognized within detected text region. Th ## Example ```tsx -import { useOCR, OCR_ENGLISH } from 'react-native-executorch'; - +import { models, useOCR } from 'react-native-executorch'; function App() { - const model = useOCR({ model: OCR_ENGLISH }); + const model = useOCR({ model: models.ocr({ language: 'en' }) }); const runModel = async () => { const ocrDetections = await model.forward('https://url-to-image.jpg'); diff --git a/docs/docs/03-hooks/02-computer-vision/useObjectDetection.md b/docs/docs/03-hooks/02-computer-vision/useObjectDetection.md index b5e0dfaf5e..317c00c3b7 100644 --- a/docs/docs/03-hooks/02-computer-vision/useObjectDetection.md +++ b/docs/docs/03-hooks/02-computer-vision/useObjectDetection.md @@ -16,13 +16,9 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```typescript -import { - useObjectDetection, - SSDLITE_320_MOBILENET_V3_LARGE, -} from 'react-native-executorch'; - +import { models, useObjectDetection } from 'react-native-executorch'; const model = useObjectDetection({ - model: SSDLITE_320_MOBILENET_V3_LARGE, + model: models.object_detection.ssdlite_320_mobilenet_v3_large(), }); const imageUri = 'file:///Users/.../photo.jpg'; @@ -84,11 +80,10 @@ To run the model, use the [`forward`](../../06-api-reference/interfaces/ObjectDe ## Example ```typescript -import { useObjectDetection, YOLO26N } from 'react-native-executorch'; - +import { models, useObjectDetection } from 'react-native-executorch'; function App() { const model = useObjectDetection({ - model: YOLO26N, + model: models.object_detection.yolo26n(), }); const handleDetect = async () => { diff --git a/docs/docs/03-hooks/02-computer-vision/usePoseEstimation.md b/docs/docs/03-hooks/02-computer-vision/usePoseEstimation.md index e31b928074..465a0ab6a6 100644 --- a/docs/docs/03-hooks/02-computer-vision/usePoseEstimation.md +++ b/docs/docs/03-hooks/02-computer-vision/usePoseEstimation.md @@ -16,10 +16,9 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```typescript -import { usePoseEstimation, YOLO26N_POSE } from 'react-native-executorch'; - +import { models, usePoseEstimation } from 'react-native-executorch'; const model = usePoseEstimation({ - model: YOLO26N_POSE, + model: models.pose_estimation.yolo26n(), }); const imageUri = 'file:///Users/.../photo.jpg'; @@ -94,11 +93,10 @@ The keypoint names available on each person are determined by the model's keypoi ## Example ```typescript -import { usePoseEstimation, YOLO26N_POSE } from 'react-native-executorch'; - +import { models, usePoseEstimation } from 'react-native-executorch'; function App() { const model = usePoseEstimation({ - model: YOLO26N_POSE, + model: models.pose_estimation.yolo26n(), }); const handleDetect = async () => { diff --git a/docs/docs/03-hooks/02-computer-vision/useSemanticSegmentation.md b/docs/docs/03-hooks/02-computer-vision/useSemanticSegmentation.md index dfc95317db..dd059cc4b6 100644 --- a/docs/docs/03-hooks/02-computer-vision/useSemanticSegmentation.md +++ b/docs/docs/03-hooks/02-computer-vision/useSemanticSegmentation.md @@ -16,13 +16,9 @@ It is recommended to use models provided by us which are available at our [Huggi ## High Level Overview ```typescript -import { - useSemanticSegmentation, - DEEPLAB_V3_RESNET50, -} from 'react-native-executorch'; - +import { models, useSemanticSegmentation } from 'react-native-executorch'; const model = useSemanticSegmentation({ - model: DEEPLAB_V3_RESNET50, + model: models.semantic_segmentation.deeplab_v3_resnet50(), }); const imageUri = 'file::///Users/.../cute_cat.png'; @@ -85,14 +81,13 @@ The return type is fully typed — TypeScript narrows it based on the labels you ```typescript import { + models, useSemanticSegmentation, - DEEPLAB_V3_RESNET50, DeeplabLabel, } from 'react-native-executorch'; - function App() { const model = useSemanticSegmentation({ - model: DEEPLAB_V3_RESNET50, + model: models.semantic_segmentation.deeplab_v3_resnet50(), }); const handleSegment = async () => { diff --git a/docs/docs/03-hooks/02-computer-vision/useStyleTransfer.md b/docs/docs/03-hooks/02-computer-vision/useStyleTransfer.md index 800a1cdc4f..f76693fdc4 100644 --- a/docs/docs/03-hooks/02-computer-vision/useStyleTransfer.md +++ b/docs/docs/03-hooks/02-computer-vision/useStyleTransfer.md @@ -16,12 +16,8 @@ It is recommended to use models provided by us which are available at our [Huggi ## High Level Overview ```typescript -import { - useStyleTransfer, - STYLE_TRANSFER_CANDY, -} from 'react-native-executorch'; - -const model = useStyleTransfer({ model: STYLE_TRANSFER_CANDY }); +import { models, useStyleTransfer } from 'react-native-executorch'; +const model = useStyleTransfer({ model: models.style_transfer.candy() }); const imageUri = 'file:///Users/.../cute_cat.png'; @@ -68,13 +64,9 @@ When `outputType` is `'url'`, the generated image is stored in your application' ## Example ```typescript -import { - useStyleTransfer, - STYLE_TRANSFER_CANDY, -} from 'react-native-executorch'; - +import { models, useStyleTransfer } from 'react-native-executorch'; function App() { - const model = useStyleTransfer({ model: STYLE_TRANSFER_CANDY }); + const model = useStyleTransfer({ model: models.style_transfer.candy() }); // Returns a file URI — easy to pass to const runWithUrl = async (imageUri: string) => { diff --git a/docs/docs/03-hooks/02-computer-vision/useTextToImage.md b/docs/docs/03-hooks/02-computer-vision/useTextToImage.md index 1968c46088..3ca063bf60 100644 --- a/docs/docs/03-hooks/02-computer-vision/useTextToImage.md +++ b/docs/docs/03-hooks/02-computer-vision/useTextToImage.md @@ -18,9 +18,10 @@ It is recommended to use models provided by us which are available at our [Huggi ## High Level Overview ```typescript -import { useTextToImage, BK_SDM_TINY_VPRED_256 } from 'react-native-executorch'; - -const model = useTextToImage({ model: BK_SDM_TINY_VPRED_256 }); +import { models, useTextToImage } from 'react-native-executorch'; +const model = useTextToImage({ + model: models.image_generation.bk_sdm_tiny_vpred_256(), +}); const input = 'a castle'; @@ -62,10 +63,11 @@ Larger imageSize values require significantly more memory to run the model. ## Example ```tsx -import { useTextToImage, BK_SDM_TINY_VPRED_256 } from 'react-native-executorch'; - +import { models, useTextToImage } from 'react-native-executorch'; function App() { - const model = useTextToImage({ model: BK_SDM_TINY_VPRED_256 }); + const model = useTextToImage({ + model: models.image_generation.bk_sdm_tiny_vpred_256(), + }); //... const input = 'a medieval castle by the sea shore'; diff --git a/docs/docs/03-hooks/02-computer-vision/useVerticalOCR.md b/docs/docs/03-hooks/02-computer-vision/useVerticalOCR.md index ff27b55e17..db5f35be66 100644 --- a/docs/docs/03-hooks/02-computer-vision/useVerticalOCR.md +++ b/docs/docs/03-hooks/02-computer-vision/useVerticalOCR.md @@ -20,11 +20,10 @@ It is recommended to use models provided by us, which are available at our [Hugg ## High Level Overview ```tsx -import { useVerticalOCR, OCR_ENGLISH } from 'react-native-executorch'; - +import { models, useVerticalOCR } from 'react-native-executorch'; function App() { const model = useVerticalOCR({ - model: OCR_ENGLISH, + model: models.ocr({ language: 'en' }), independentCharacters: true, }); @@ -89,11 +88,10 @@ The `text` property contains the text recognized within detected text region. Th ## Example ```tsx -import { useVerticalOCR, OCR_ENGLISH } from 'react-native-executorch'; - +import { models, useVerticalOCR } from 'react-native-executorch'; function App() { const model = useVerticalOCR({ - model: OCR_ENGLISH, + model: models.ocr({ language: 'en' }), independentCharacters: true, }); diff --git a/docs/docs/03-hooks/02-computer-vision/visioncamera-integration.md b/docs/docs/03-hooks/02-computer-vision/visioncamera-integration.md index b96b7f5274..b421047552 100644 --- a/docs/docs/03-hooks/02-computer-vision/visioncamera-integration.md +++ b/docs/docs/03-hooks/02-computer-vision/visioncamera-integration.md @@ -78,17 +78,14 @@ import { useFrameOutput, } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; -import { - Detection, - useObjectDetection, - SSDLITE_320_MOBILENET_V3_LARGE, -} from 'react-native-executorch'; - +import { models, Detection, useObjectDetection } from 'react-native-executorch'; export default function App() { const { hasPermission, requestPermission } = useCameraPermission(); const devices = useCameraDevices(); const device = devices.find((d) => d.position === 'back'); - const model = useObjectDetection({ model: SSDLITE_320_MOBILENET_V3_LARGE }); + const model = useObjectDetection({ + model: models.object_detection.ssdlite_320_mobilenet_v3_large(), + }); const [detections, setDetections] = useState([]); const detRof = model.runOnFrame; @@ -211,11 +208,7 @@ import { useFrameOutput, } from 'react-native-vision-camera'; import { scheduleOnRN } from 'react-native-worklets'; -import { - ClassificationModule, - EFFICIENTNET_V2_S, -} from 'react-native-executorch'; - +import { models, ClassificationModule } from 'react-native-executorch'; export default function App() { const { hasPermission, requestPermission } = useCameraPermission(); const device = useCameraDevice('back'); @@ -227,7 +220,9 @@ export default function App() { }, [hasPermission, requestPermission]); useEffect(() => { - ClassificationModule.fromModelName(EFFICIENTNET_V2_S).then((module) => { + ClassificationModule.fromModelName( + models.classification.efficientnet_v2_s() + ).then((module) => { // () => module.runOnFrame is required — passing module.runOnFrame directly // would cause React to call it as a state initializer function setRunOnFrame(() => module.runOnFrame); diff --git a/docs/docs/03-hooks/03-executorch-bindings/useExecutorchModule.md b/docs/docs/03-hooks/03-executorch-bindings/useExecutorchModule.md index f51733307b..7429b4b60e 100644 --- a/docs/docs/03-hooks/03-executorch-bindings/useExecutorchModule.md +++ b/docs/docs/03-hooks/03-executorch-bindings/useExecutorchModule.md @@ -18,7 +18,6 @@ You can initialize the ExecuTorch module in your JavaScript application using th ```typescript import { useExecutorchModule } from 'react-native-executorch'; - const executorchModule = useExecutorchModule({ modelSource: require('../assets/models/model.pte'), }); @@ -64,14 +63,13 @@ First, import the necessary functions from the `react-native-executorch` package ```typescript import { + models, useExecutorchModule, - STYLE_TRANSFER_CANDY, ScalarType, } from 'react-native-executorch'; - // Initialize the executorch module with the predefined style transfer model. const executorchModule = useExecutorchModule({ - modelSource: STYLE_TRANSFER_CANDY, + modelSource: models.style_transfer.candy(), }); ``` diff --git a/docs/docs/04-typescript-api/01-natural-language-processing/LLMModule.md b/docs/docs/04-typescript-api/01-natural-language-processing/LLMModule.md index c1cf24a9fc..949b39f72d 100644 --- a/docs/docs/04-typescript-api/01-natural-language-processing/LLMModule.md +++ b/docs/docs/04-typescript-api/01-natural-language-processing/LLMModule.md @@ -13,11 +13,10 @@ TypeScript API implementation of the [useLLM](../../03-hooks/01-natural-language ## High Level Overview ```typescript -import { LLMModule, LFM2_5_1_2B_INSTRUCT } from 'react-native-executorch'; - +import { models, LLMModule } from 'react-native-executorch'; // Creating an instance and loading the model const llm = await LLMModule.fromModelName( - LFM2_5_1_2B_INSTRUCT, + models.llm.lfm2_5_1_2b_instruct(), (progress) => console.log(progress), (token) => console.log(token), (messages) => console.log(messages) @@ -44,7 +43,7 @@ Use the static [`fromModelName`](../../06-api-reference/classes/LLMModule.md#fro ```typescript const llm = await LLMModule.fromModelName( - LFM2_5_1_2B_INSTRUCT, // model config constant + models.llm.lfm2_5_1_2b_instruct(), // model config constant onDownloadProgress, // optional, progress 0–1 tokenCallback, // optional, called on every token messageHistoryCallback // optional, called when generation finishes @@ -122,10 +121,9 @@ Model presets expose an optional `generationConfig` that `LLMModule.fromModelNam Some models support multimodal input — text and images together. To use them, pass `capabilities` in the model object when calling [`fromModelName`](../../06-api-reference/classes/LLMModule.md#frommodelname): ```typescript -import { LLMModule, LFM2_5_VL_1_6B_QUANTIZED } from 'react-native-executorch'; - +import { models, LLMModule } from 'react-native-executorch'; const llm = await LLMModule.fromModelName( - LFM2_5_VL_1_6B_QUANTIZED, + models.lmm.lfm2_5_vl_1_6b(), undefined, (token) => console.log(token) ); @@ -171,7 +169,6 @@ Use [`fromCustomModel`](../../06-api-reference/classes/LLMModule.md#fromcustommo ```typescript import { LLMModule } from 'react-native-executorch'; - const llm = await LLMModule.fromCustomModel( 'https://example.com/model.pte', 'https://example.com/tokenizer.json', diff --git a/docs/docs/04-typescript-api/01-natural-language-processing/PrivacyFilterModule.md b/docs/docs/04-typescript-api/01-natural-language-processing/PrivacyFilterModule.md index a862bce3bb..2df0f7dff0 100644 --- a/docs/docs/04-typescript-api/01-natural-language-processing/PrivacyFilterModule.md +++ b/docs/docs/04-typescript-api/01-natural-language-processing/PrivacyFilterModule.md @@ -12,13 +12,9 @@ TypeScript API implementation of the [usePrivacyFilter](../../03-hooks/01-natura ## High Level Overview ```typescript -import { - PrivacyFilterModule, - PRIVACY_FILTER_OPENAI, -} from 'react-native-executorch'; - +import { models, PrivacyFilterModule } from 'react-native-executorch'; const model = await PrivacyFilterModule.fromModelName( - PRIVACY_FILTER_OPENAI, + models.privacy_filter.openai(), (progress) => console.log(progress) ); diff --git a/docs/docs/04-typescript-api/01-natural-language-processing/SpeechToTextModule.md b/docs/docs/04-typescript-api/01-natural-language-processing/SpeechToTextModule.md index d4d8897e7c..de5d763db9 100644 --- a/docs/docs/04-typescript-api/01-natural-language-processing/SpeechToTextModule.md +++ b/docs/docs/04-typescript-api/01-natural-language-processing/SpeechToTextModule.md @@ -12,10 +12,9 @@ TypeScript API implementation of the [useSpeechToText](../../03-hooks/01-natural ## High Level Overview ```typescript -import { SpeechToTextModule, WHISPER_TINY_EN } from 'react-native-executorch'; - +import { models, SpeechToTextModule } from 'react-native-executorch'; const model = await SpeechToTextModule.fromModelName( - WHISPER_TINY_EN, + models.speech_to_text.whisper_tiny_en(), (progress) => { console.log(progress); } @@ -65,10 +64,9 @@ To run the model, you can use the [`transcribe`](../../06-api-reference/classes/ If you aim to obtain a transcription in other languages than English, use the multilingual version of whisper. To obtain the output text in your desired language, pass the [`DecodingOptions`](../../06-api-reference/interfaces/DecodingOptions.md) object with the [`language`](../../06-api-reference/interfaces/DecodingOptions.md#language) field set to your desired language code. ```typescript -import { SpeechToTextModule, WHISPER_TINY } from 'react-native-executorch'; - +import { models, SpeechToTextModule } from 'react-native-executorch'; const model = await SpeechToTextModule.fromModelName( - WHISPER_TINY, + models.speech_to_text.whisper_tiny(), (progress) => { console.log(progress); } @@ -118,14 +116,14 @@ const transcription = await model.transcribe(audioBuffer, { verbose: true }); ### Transcription ```tsx -import { SpeechToTextModule, WHISPER_TINY_EN } from 'react-native-executorch'; +import { models, SpeechToTextModule } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; import * as FileSystem from 'expo-file-system'; const transcribeAudio = async () => { // Initialize with the model config const model = await SpeechToTextModule.fromModelName( - WHISPER_TINY_EN, + models.speech_to_text.whisper_tiny_en(), (progress) => { console.log(progress); } @@ -164,12 +162,12 @@ const transcribeAudio = async () => { ### Streaming Transcription ```tsx -import { SpeechToTextModule, WHISPER_TINY_EN } from 'react-native-executorch'; +import { models, SpeechToTextModule } from 'react-native-executorch'; import { AudioManager, AudioRecorder } from 'react-native-audio-api'; // Load the model const model = await SpeechToTextModule.fromModelName( - WHISPER_TINY_EN, + models.speech_to_text.whisper_tiny_en(), (progress) => { console.log(progress); } diff --git a/docs/docs/04-typescript-api/01-natural-language-processing/TextEmbeddingsModule.md b/docs/docs/04-typescript-api/01-natural-language-processing/TextEmbeddingsModule.md index 054299290b..aa563c213d 100644 --- a/docs/docs/04-typescript-api/01-natural-language-processing/TextEmbeddingsModule.md +++ b/docs/docs/04-typescript-api/01-natural-language-processing/TextEmbeddingsModule.md @@ -12,14 +12,11 @@ TypeScript API implementation of the [useTextEmbeddings](../../03-hooks/01-natur ## High Level Overview ```typescript -import { - TextEmbeddingsModule, - ALL_MINILM_L6_V2, -} from 'react-native-executorch'; - +import { models, TextEmbeddingsModule } from 'react-native-executorch'; // Creating an instance and loading the model -const textEmbeddingsModule = - await TextEmbeddingsModule.fromModelName(ALL_MINILM_L6_V2); +const textEmbeddingsModule = await TextEmbeddingsModule.fromModelName( + models.text_embedding.all_minilm_l6_v2() +); // Running the model const embedding = await textEmbeddingsModule.forward('Hello World!'); diff --git a/docs/docs/04-typescript-api/01-natural-language-processing/TextToSpeechModule.md b/docs/docs/04-typescript-api/01-natural-language-processing/TextToSpeechModule.md index ec0919574c..3ce7231345 100644 --- a/docs/docs/04-typescript-api/01-natural-language-processing/TextToSpeechModule.md +++ b/docs/docs/04-typescript-api/01-natural-language-processing/TextToSpeechModule.md @@ -13,14 +13,12 @@ TypeScript API implementation of the [useTextToSpeech](../../03-hooks/01-natural ## High Level Overview ```typescript -import { - TextToSpeechModule, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; - +import { models, TextToSpeechModule } from 'react-native-executorch'; const model = await TextToSpeechModule.fromModelName( - { model: KOKORO_MEDIUM, voice: KOKORO_VOICE_AF_HEART }, + { + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, + }, (progress) => console.log(progress) ); @@ -70,16 +68,12 @@ Since `forward` and `forwardFromPhonemes` process the entire input at once, they ### Speech Synthesis ```typescript -import { - TextToSpeechModule, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; +import { models, TextToSpeechModule } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; const tts = await TextToSpeechModule.fromModelName({ - model: KOKORO_MEDIUM, - voice: KOKORO_VOICE_AF_HEART, + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, }); const audioContext = new AudioContext({ sampleRate: 24000 }); @@ -102,16 +96,12 @@ try { ### Streaming Synthesis ```typescript -import { - TextToSpeechModule, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; +import { models, TextToSpeechModule } from 'react-native-executorch'; import { AudioContext } from 'react-native-audio-api'; const tts = await TextToSpeechModule.fromModelName({ - model: KOKORO_MEDIUM, - voice: KOKORO_VOICE_AF_HEART, + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, }); const audioContext = new AudioContext({ sampleRate: 24000 }); @@ -142,15 +132,10 @@ try { If you already have a phoneme string (e.g., from an external library), you can use `forwardFromPhonemes` or `streamFromPhonemes` to synthesize audio directly, skipping the internal phonemizer stage. ```typescript -import { - TextToSpeechModule, - KOKORO_MEDIUM, - KOKORO_VOICE_AF_HEART, -} from 'react-native-executorch'; - +import { models, TextToSpeechModule } from 'react-native-executorch'; const tts = await TextToSpeechModule.fromModelName({ - model: KOKORO_MEDIUM, - voice: KOKORO_VOICE_AF_HEART, + model: models.text_to_speech.kokoro_medium(), + voice: models.text_to_speech.voices.af_heart, }); // Example phonemes for "ExecuTorch" diff --git a/docs/docs/04-typescript-api/01-natural-language-processing/TokenizerModule.md b/docs/docs/04-typescript-api/01-natural-language-processing/TokenizerModule.md index dffdfba867..f85178fe09 100644 --- a/docs/docs/04-typescript-api/01-natural-language-processing/TokenizerModule.md +++ b/docs/docs/04-typescript-api/01-natural-language-processing/TokenizerModule.md @@ -11,13 +11,12 @@ TypeScript API implementation of the [useTokenizer](../../03-hooks/01-natural-la ## High Level Overview ```typescript -import { TokenizerModule, ALL_MINILM_L6_V2 } from 'react-native-executorch'; - +import { models, TokenizerModule } from 'react-native-executorch'; // Creating an instance const tokenizerModule = new TokenizerModule(); // Load the tokenizer -await tokenizerModule.load(ALL_MINILM_L6_V2); +await tokenizerModule.load(models.text_embedding.all_minilm_l6_v2()); console.log('Tokenizer loaded'); // Get tokenizers vocabulary size diff --git a/docs/docs/04-typescript-api/01-natural-language-processing/VADModule.md b/docs/docs/04-typescript-api/01-natural-language-processing/VADModule.md index d32a7c3920..e9dd56710e 100644 --- a/docs/docs/04-typescript-api/01-natural-language-processing/VADModule.md +++ b/docs/docs/04-typescript-api/01-natural-language-processing/VADModule.md @@ -12,9 +12,8 @@ TypeScript API implementation of the [useVAD](../../03-hooks/01-natural-language ## High Level Overview ```typescript -import { VADModule, FSMN_VAD } from 'react-native-executorch'; - -const model = await VADModule.fromModelName(FSMN_VAD, (progress) => +import { models, VADModule } from 'react-native-executorch'; +const model = await VADModule.fromModelName(models.vad.fsmn_vad(), (progress) => console.log(progress) ); diff --git a/docs/docs/04-typescript-api/02-computer-vision/ClassificationModule.md b/docs/docs/04-typescript-api/02-computer-vision/ClassificationModule.md index 256e918123..8f7802686c 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/ClassificationModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/ClassificationModule.md @@ -12,16 +12,13 @@ TypeScript API implementation of the [useClassification](../../03-hooks/02-compu ## High Level Overview ```typescript -import { - ClassificationModule, - EFFICIENTNET_V2_S, -} from 'react-native-executorch'; - +import { models, ClassificationModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating and loading the module -const classificationModule = - await ClassificationModule.fromModelName(EFFICIENTNET_V2_S); +const classificationModule = await ClassificationModule.fromModelName( + models.classification.efficientnet_v2_s() +); // Running the model const classesWithProbabilities = await classificationModule.forward(imageUri); @@ -49,7 +46,6 @@ Use [`fromCustomModel`](../../06-api-reference/classes/ClassificationModule.md#f ```typescript import { ClassificationModule } from 'react-native-executorch'; - const MyLabels = { CAT: 0, DOG: 1, BIRD: 2 } as const; const classifier = await ClassificationModule.fromCustomModel( diff --git a/docs/docs/04-typescript-api/02-computer-vision/ImageEmbeddingsModule.md b/docs/docs/04-typescript-api/02-computer-vision/ImageEmbeddingsModule.md index 47eceef00a..132245a3f5 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/ImageEmbeddingsModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/ImageEmbeddingsModule.md @@ -12,14 +12,10 @@ TypeScript API implementation of the [useImageEmbeddings](../../03-hooks/02-comp ## High Level Overview ```typescript -import { - ImageEmbeddingsModule, - CLIP_VIT_BASE_PATCH32_IMAGE, -} from 'react-native-executorch'; - +import { models, ImageEmbeddingsModule } from 'react-native-executorch'; // Creating and loading the module const imageEmbeddingsModule = await ImageEmbeddingsModule.fromModelName( - CLIP_VIT_BASE_PATCH32_IMAGE + models.image_embedding.clip_vit_base_patch32_image() ); // Running the model diff --git a/docs/docs/04-typescript-api/02-computer-vision/InstanceSegmentationModule.md b/docs/docs/04-typescript-api/02-computer-vision/InstanceSegmentationModule.md index 6363de61f5..1403cfb21e 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/InstanceSegmentationModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/InstanceSegmentationModule.md @@ -11,16 +11,13 @@ TypeScript API implementation of the [useInstanceSegmentation](../../03-hooks/02 ## High Level Overview ```typescript -import { - InstanceSegmentationModule, - YOLO26N_SEG, -} from 'react-native-executorch'; - +import { models, InstanceSegmentationModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating an instance from a built-in model -const segmentation = - await InstanceSegmentationModule.fromModelName(YOLO26N_SEG); +const segmentation = await InstanceSegmentationModule.fromModelName( + models.instance_segmentation.yolo26n_seg() +); // Running the model const instances = await segmentation.forward(imageUri); @@ -44,13 +41,10 @@ Use [`fromModelName`](../../06-api-reference/classes/InstanceSegmentationModule. - `onDownloadProgress` (optional) - Callback to track download progress, receiving a value between 0 and 1. ```typescript -import { - InstanceSegmentationModule, - YOLO26N_SEG, -} from 'react-native-executorch'; - -const segmentation = - await InstanceSegmentationModule.fromModelName(YOLO26N_SEG); +import { models, InstanceSegmentationModule } from 'react-native-executorch'; +const segmentation = await InstanceSegmentationModule.fromModelName( + models.instance_segmentation.yolo26n_seg() +); ``` ### From a custom config diff --git a/docs/docs/04-typescript-api/02-computer-vision/OCRModule.md b/docs/docs/04-typescript-api/02-computer-vision/OCRModule.md index 1391982173..ec5aa24184 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/OCRModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/OCRModule.md @@ -12,11 +12,11 @@ TypeScript API implementation of the [useOCR](../../03-hooks/02-computer-vision/ ## High Level Overview ```typescript -import { OCRModule, OCR_ENGLISH } from 'react-native-executorch'; +import { models, OCRModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating an instance and loading the model -const ocrModule = await OCRModule.fromModelName(OCR_ENGLISH); +const ocrModule = await OCRModule.fromModelName(models.ocr({ language: 'en' })); // Running the model const detections = await ocrModule.forward(imageUri); diff --git a/docs/docs/04-typescript-api/02-computer-vision/ObjectDetectionModule.md b/docs/docs/04-typescript-api/02-computer-vision/ObjectDetectionModule.md index 0d004e6752..4b1e19982f 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/ObjectDetectionModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/ObjectDetectionModule.md @@ -12,16 +12,12 @@ TypeScript API implementation of the [useObjectDetection](../../03-hooks/02-comp ## High Level Overview ```typescript -import { - ObjectDetectionModule, - SSDLITE_320_MOBILENET_V3_LARGE, -} from 'react-native-executorch'; - +import { models, ObjectDetectionModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating an instance and loading the model const objectDetectionModule = await ObjectDetectionModule.fromModelName( - SSDLITE_320_MOBILENET_V3_LARGE + models.object_detection.ssdlite_320_mobilenet_v3_large() ); // Running the model @@ -69,7 +65,6 @@ Use [`fromCustomModel`](../../06-api-reference/classes/ObjectDetectionModule.md# ```typescript import { ObjectDetectionModule } from 'react-native-executorch'; - const MyLabels = { BACKGROUND: 0, CAT: 1, DOG: 2 } as const; const detector = await ObjectDetectionModule.fromCustomModel( diff --git a/docs/docs/04-typescript-api/02-computer-vision/PoseEstimationModule.md b/docs/docs/04-typescript-api/02-computer-vision/PoseEstimationModule.md index bc32211b19..f8c2c7a173 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/PoseEstimationModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/PoseEstimationModule.md @@ -12,13 +12,13 @@ TypeScript API implementation of the [usePoseEstimation](../../03-hooks/02-compu ## High Level Overview ```typescript -import { PoseEstimationModule, YOLO26N_POSE } from 'react-native-executorch'; - +import { models, PoseEstimationModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating an instance and loading the model -const poseEstimationModule = - await PoseEstimationModule.fromModelName(YOLO26N_POSE); +const poseEstimationModule = await PoseEstimationModule.fromModelName( + models.pose_estimation.yolo26n() +); // Running the model const detections = await poseEstimationModule.forward(imageUri); @@ -72,7 +72,6 @@ Use [`fromCustomModel`](../../06-api-reference/classes/PoseEstimationModule.md#f ```typescript import { PoseEstimationModule } from 'react-native-executorch'; - const HandKeypoints = { WRIST: 0, THUMB_TIP: 1, diff --git a/docs/docs/04-typescript-api/02-computer-vision/SemanticSegmentationModule.md b/docs/docs/04-typescript-api/02-computer-vision/SemanticSegmentationModule.md index b248f2876e..fffe2a7ba1 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/SemanticSegmentationModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/SemanticSegmentationModule.md @@ -12,16 +12,13 @@ TypeScript API implementation of the [useSemanticSegmentation](../../03-hooks/02 ## High Level Overview ```typescript -import { - SemanticSegmentationModule, - DEEPLAB_V3_RESNET50, -} from 'react-native-executorch'; - +import { models, SemanticSegmentationModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating an instance from a built-in model -const segmentation = - await SemanticSegmentationModule.fromModelName(DEEPLAB_V3_RESNET50); +const segmentation = await SemanticSegmentationModule.fromModelName( + models.semantic_segmentation.deeplab_v3_resnet50() +); // Running the model const result = await segmentation.forward(imageUri); @@ -42,7 +39,7 @@ Use [`fromModelName`](../../06-api-reference/classes/SemanticSegmentationModule. ```typescript const segmentation = await SemanticSegmentationModule.fromModelName( - DEEPLAB_V3_RESNET50, + models.semantic_segmentation.deeplab_v3_resnet50(), (progress) => console.log(`Download: ${Math.round(progress * 100)}%`) ); ``` diff --git a/docs/docs/04-typescript-api/02-computer-vision/StyleTransferModule.md b/docs/docs/04-typescript-api/02-computer-vision/StyleTransferModule.md index 4c57716001..966cdff58b 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/StyleTransferModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/StyleTransferModule.md @@ -12,16 +12,13 @@ TypeScript API implementation of the [useStyleTransfer](../../03-hooks/02-comput ## High Level Overview ```typescript -import { - StyleTransferModule, - STYLE_TRANSFER_CANDY, -} from 'react-native-executorch'; - +import { models, StyleTransferModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating and loading the module -const styleTransferModule = - await StyleTransferModule.fromModelName(STYLE_TRANSFER_CANDY); +const styleTransferModule = await StyleTransferModule.fromModelName( + models.style_transfer.candy() +); // Running the model const generatedImageUrl = await styleTransferModule.forward(imageUri); diff --git a/docs/docs/04-typescript-api/02-computer-vision/TextToImageModule.md b/docs/docs/04-typescript-api/02-computer-vision/TextToImageModule.md index d6ade747bd..cf73eee019 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/TextToImageModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/TextToImageModule.md @@ -12,16 +12,12 @@ TypeScript API implementation of the [useTextToImage](../../03-hooks/02-computer ## High Level Overview ```typescript -import { - TextToImageModule, - BK_SDM_TINY_VPRED_256, -} from 'react-native-executorch'; - +import { models, TextToImageModule } from 'react-native-executorch'; const input = 'a castle'; // Creating an instance and loading the model const textToImageModule = await TextToImageModule.fromModelName( - BK_SDM_TINY_VPRED_256 + models.image_generation.bk_sdm_tiny_vpred_256() ); // Running the model diff --git a/docs/docs/04-typescript-api/02-computer-vision/VerticalOCRModule.md b/docs/docs/04-typescript-api/02-computer-vision/VerticalOCRModule.md index cc1cdba51d..17be3d2866 100644 --- a/docs/docs/04-typescript-api/02-computer-vision/VerticalOCRModule.md +++ b/docs/docs/04-typescript-api/02-computer-vision/VerticalOCRModule.md @@ -12,12 +12,13 @@ TypeScript API implementation of the [useVerticalOCR](../../03-hooks/02-computer ## High Level Overview ```typescript -import { VerticalOCRModule, OCR_ENGLISH } from 'react-native-executorch'; - +import { models, VerticalOCRModule } from 'react-native-executorch'; const imageUri = 'path/to/image.png'; // Creating an instance and loading the model -const verticalOCRModule = await VerticalOCRModule.fromModelName(OCR_ENGLISH); +const verticalOCRModule = await VerticalOCRModule.fromModelName( + models.ocr({ language: 'en' }) +); // Running the model const detections = await verticalOCRModule.forward(imageUri); diff --git a/docs/docs/04-typescript-api/03-executorch-bindings/ExecutorchModule.md b/docs/docs/04-typescript-api/03-executorch-bindings/ExecutorchModule.md index 099379b333..252f7fa74a 100644 --- a/docs/docs/04-typescript-api/03-executorch-bindings/ExecutorchModule.md +++ b/docs/docs/04-typescript-api/03-executorch-bindings/ExecutorchModule.md @@ -15,12 +15,7 @@ For React applications, consider using the [`useExecutorchModule`](../../03-hook ## High Level Overview ```typescript -import { - ExecutorchModule, - STYLE_TRANSFER_CANDY, - ScalarType, -} from 'react-native-executorch'; - +import { models, ExecutorchModule, ScalarType } from 'react-native-executorch'; // Creating the input array const inputTensor = { dataPtr: new Float32Array(1 * 3 * 640 * 640), @@ -32,7 +27,7 @@ const inputTensor = { const model = new ExecutorchModule(); // Loading the model -await model.load(STYLE_TRANSFER_CANDY); +await model.load(models.style_transfer.candy()); // Running the forward method const output = await model.forward([inputTensor]); @@ -61,17 +56,12 @@ This example demonstrates the integration and usage of the ExecuTorch bindings w First, import the necessary functions from the `react-native-executorch` package and initialize the ExecuTorch module with the specified style transfer model. ```typescript -import { - ExecutorchModule, - STYLE_TRANSFER_CANDY, - ScalarType, -} from 'react-native-executorch'; - +import { models, ExecutorchModule, ScalarType } from 'react-native-executorch'; // Initialize the executorch module const executorchModule = new ExecutorchModule(); // Load the model with optional download progress callback -await executorchModule.load(STYLE_TRANSFER_CANDY, (progress) => { +await executorchModule.load(models.style_transfer.candy(), (progress) => { console.log(`Download progress: ${progress}%`); }); ``` diff --git a/docs/docs/05-utilities/04-error-handling.md b/docs/docs/05-utilities/04-error-handling.md index d295fbe945..3e1b9d9fe6 100644 --- a/docs/docs/05-utilities/04-error-handling.md +++ b/docs/docs/05-utilities/04-error-handling.md @@ -10,14 +10,13 @@ This example uses the `LLMModule`, and then tries to change its `generationConfi ```typescript import { + models, LLMModule, - LFM2_5_1_2B_INSTRUCT, RnExecutorchError, RnExecutorchErrorCode, } from 'react-native-executorch'; - const llm = await LLMModule.fromModelName( - LFM2_5_1_2B_INSTRUCT, + models.llm.lfm2_5_1_2b_instruct(), (progress) => console.log(progress), (token) => console.log(token), (messages) => console.log(messages) diff --git a/docs/docs/05-utilities/model-registry.md b/docs/docs/05-utilities/model-registry.md index 586d32e91e..aab9d0fab9 100644 --- a/docs/docs/05-utilities/model-registry.md +++ b/docs/docs/05-utilities/model-registry.md @@ -23,9 +23,11 @@ Each leaf is a **function**. Call it (optionally with `{ quant, backend }`) to g | Group | Examples | | ----------------------- | ----------------------------------------------------------------------------------------------------------- | | `llm` | `llama3_2_3b`, `qwen3_4b`, `smollm2_1_1_7b`, `phi_4_mini_4b`, `bielik_v3_0_1_5b`, `lfm2_5_1_2b_instruct`, … | -| `multimodal` | `lfm2_5_vl_1_6b`, `lfm2_5_vl_450m` | -| `classification` | `efficientnet_v2_s`, `privacy_filter_openai`, `privacy_filter_nemotron` | +| `lmm` | `lfm2_5_vl_1_6b`, `lfm2_5_vl_450m` | +| `classification` | `efficientnet_v2_s` | +| `privacy_filter` | `openai`, `nemotron` | | `object_detection` | `ssdlite_320_mobilenet_v3_large`, `yolo26n` … `yolo26x`, `rf_detr_nano`, `fastsam_s`, `fastsam_x` | +| `pose_estimation` | `yolo26n` | | `semantic_segmentation` | `deeplab_v3_resnet50`, `lraspp_mobilenet_v3_large`, `fcn_resnet101`, `selfie_segmentation`, … | | `instance_segmentation` | `yolo26n_seg` … `yolo26x_seg`, `rf_detr_nano_seg` | | `style_transfer` | `candy`, `mosaic`, `rain_princess`, `udnie` | diff --git a/docs/docs/08-resource-fetcher/02-custom-adapter.md b/docs/docs/08-resource-fetcher/02-custom-adapter.md index 36d25a888d..22773b3f47 100644 --- a/docs/docs/08-resource-fetcher/02-custom-adapter.md +++ b/docs/docs/08-resource-fetcher/02-custom-adapter.md @@ -13,7 +13,6 @@ import { ResourceFetcherAdapter, ResourceSource, } from 'react-native-executorch'; - interface ResourceFetcherAdapter { fetch( callback: (downloadProgress: number) => void,