Skip to content

refactor!: add static factories for remaining models#937

Merged
chmjkb merged 23 commits intomainfrom
@chmjkb/static-factories-refactor
Mar 13, 2026
Merged

refactor!: add static factories for remaining models#937
chmjkb merged 23 commits intomainfrom
@chmjkb/static-factories-refactor

Conversation

@chmjkb
Copy link
Collaborator

@chmjkb chmjkb commented Mar 5, 2026

Description

This PR refactors the existing codebase to match what has been recently done with object detection & semantic segmentation. Namely, it changes the model initialization flow from new Module() -> module.load() to a single, static factory, for example: fromModelName(modelName)

All affected modules now follow the same two-method factory API:

  • Module.fromModelName(namedSources, onDownloadProgress?) — for built-in models. Requires a modelName field (typed literal union, e.g. LLMModelName, SpeechToTextModelName) that will be used for telemetry once that infrastructure is in place.
  • Module.fromCustomModel(...sources, onDownloadProgress?) — for user-provided model binaries. Does not expose a modelName parameter — users with custom models shouldn't need to know about or satisfy a type constraint that exists purely for internal tracking.

Note: for now fromCustomModel internally delegates to fromModelName with a 'custom' placeholder. The two methods will diverge meaningfully once telemetry is wired up.

Modules migrated

Module Notes
ClassificationModule factory + fromCustomModel
StyleTransferModule factory + fromCustomModel
ImageEmbeddingsModule factory + fromCustomModel
VADModule factory + fromCustomModel
TextEmbeddingsModule factory + fromCustomModel
OCRModule factory + fromCustomModel, typed OCRModelName
VerticalOCRModule factory + fromCustomModel
LLMModule factory + fromCustomModel, typed LLMModelName
SpeechToTextModule factory + fromCustomModel, typed SpeechToTextModelName
TextToImageModule factory + fromCustomModel, typed TextToImageModelName
ObjectDetectionModule fromCustomConfigfromCustomModel rename
SemanticSegmentationModule fromCustomConfigfromCustomModel rename

TextToSpeechModule is not included — handled separately.

Hook updates

Hooks for modules that have a controller (OCRModule, VerticalOCRModule, LLMModule) already used the controller directly and remain unchanged in structure. Hooks for the remaining migrated modules (useSpeechToText, useTextToImage) were updated to use the factory instead of new Module() + load().

All hooks now include modelName in their useEffect dependency arrays, enabling correct reload behavior when switching between built-in models.

Typed model name unions

Each module now has a corresponding typed union (e.g. LLMModelName, SpeechToTextModelName, OCRModelName) derived from the existing model constants. This replaces the previous use of untyped string and provides compile-time safety when passing model identifiers.

Introduces a breaking change?

  • Yes
  • No

Type of change

  • Bug fix (change which fixes an issue)
  • New feature (change which adds functionality)
  • Documentation update (improves or adds clarity to existing documentation)
  • Other (chores, tests, code style improvements etc.)

Tested on

  • iOS
  • Android

Testing instructions

  • Run demo apps and check if they work.
  • Try to pass model name that is incorrect to check if error is correctly risen.
  • Try using fromCustomModel method.

Screenshots

Related issues

Checklist

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings

Additional notes

@chmjkb chmjkb marked this pull request as ready for review March 5, 2026 14:06
@chmjkb chmjkb marked this pull request as draft March 5, 2026 14:19
@chmjkb chmjkb marked this pull request as ready for review March 6, 2026 08:12
Copy link
Contributor

@NorbertKlockiewicz NorbertKlockiewicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@benITo47
Copy link
Contributor

benITo47 commented Mar 6, 2026

Code looks good - didn't run it though.

@msluszniak
Copy link
Member

@chmjkb is there anything to test other then running all the demo apps?

@chmjkb
Copy link
Collaborator Author

chmjkb commented Mar 9, 2026

@chmjkb is there anything to test other then running all the demo apps?

Other than testing the demo apps I think we're good. Maybe checking if type errors occur when unsupported model names are passed would make sense.

@msluszniak msluszniak marked this pull request as draft March 9, 2026 13:02
@chmjkb chmjkb marked this pull request as ready for review March 10, 2026 10:26
@msluszniak
Copy link
Member

Could we start with a rebase, it will be easier to review it ;p

@chmjkb
Copy link
Collaborator Author

chmjkb commented Mar 11, 2026

Could we start with a rebase, it will be easier to review it ;p

I'll rebase once all the other PRs are merged, so let's wait with the reviews until that happens 😅
image

@benITo47
Copy link
Contributor

Overall looks good, checked the apps - they work. fromCustomModel also produces expected results.

Fix the docs I marked above, add more info about fromCustomModel to the docs and it's ready to ship!

chmjkb and others added 9 commits March 12, 2026 11:16
- Remove abstract load() from BaseModule (enables clean factory subclasses)
- Remove no-op load() overrides from BaseLabeledModule and VisionLabeledModule
- Add deps parameter to useModuleFactory, relax Config generic constraint
- Update useObjectDetection and useSemanticSegmentation to pass explicit deps
- Convert ClassificationModule: private constructor + static fromModelName()
- Migrate useClassification from useModule to useModuleFactory

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nd telemetry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…to fromCustomModel

Also fix the misaligned JSDoc on ObjectDetectionModule where the
fromCustomConfig doc block was placed before forward() instead of
before fromCustomConfig itself.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ddings, VAD, TextEmbeddings

Each fromCustomModel delegates to fromModelName with modelName cast to the
built-in name type, allowing custom model binaries without requiring a
built-in preset name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chmjkb and others added 5 commits March 12, 2026 11:40
…eOCR hook

- Add OCRModelName = `ocr-${OCRLanguage}` type to types/ocr.ts
- Add modelName: OCRModelName to OCRProps.model
- Replace public constructor + load() with private constructor + fromModelName() + fromCustomModel()
- Rewrite useOCR to use useModuleFactory with OCRModule.fromModelName

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… controllers

- VerticalOCRModule: private constructor, fromModelName, fromCustomModel
- useOCR: custom hook using OCRController directly (not useModuleFactory)
- useVerticalOCR: custom hook using VerticalOCRController directly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add LLMModelName union type
- Add modelName to LLMProps.model
- LLMModule: private constructor, fromModelName, fromCustomModel
- useLLM: add model.modelName to deps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tModelName type

- Add SpeechToTextModelName union type
- Add modelName to SpeechToTextModelConfig
- SpeechToTextModule: private constructor, fromModelName, fromCustomModel
- useSpeechToText: use factory, add model.modelName to deps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…odelName type

- Add TextToImageModelName union type
- Add modelName to TextToImageProps.model
- TextToImageModule: private constructor, fromModelName, fromCustomModel
- useTextToImage: use factory, add model.modelName to deps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chmjkb chmjkb force-pushed the @chmjkb/static-factories-refactor branch from ba35183 to 86b5021 Compare March 12, 2026 10:56
@chmjkb chmjkb marked this pull request as draft March 12, 2026 10:57
@chmjkb chmjkb marked this pull request as ready for review March 12, 2026 15:40
@@ -763,6 +797,7 @@ export const FCN_RESNET101_QUANTIZED = {
} as const;

const SELFIE_SEGMENTATION_MODEL = `${URL_PREFIX}-selfie-segmentation/${NEXT_VERSION_TAG}/xnnpack/selfie-segmentation.pte`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no xnnpack directory so this link is wrong

Suggested change
const SELFIE_SEGMENTATION_MODEL = `${URL_PREFIX}-selfie-segmentation/${NEXT_VERSION_TAG}/xnnpack/selfie-segmentation.pte`;
const SELFIE_SEGMENTATION_MODEL = `${URL_PREFIX}-selfie-segmentation/${NEXT_VERSION_TAG}/selfie-segmentation.pte`;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it shoudl be added. So instead of modifying the URL I'll modify the repo so it's aligned iwht other models

chmjkb and others added 2 commits March 13, 2026 08:46
…Module.md

Co-authored-by: Norbert Klockiewicz <Nklockiewicz12@gmail.com>
Copy link
Contributor

@NorbertKlockiewicz NorbertKlockiewicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I run few example apps and didn't encounter any errors.

Copy link
Member

@msluszniak msluszniak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got an error when running text to image example:

 ERROR  [TypeError: this.nativeModule.generate is not a function (it is undefined)] 

Code: TextToImageModule.ts
  164 |     seed?: number
  165 |   ): Promise<string> {
> 166 |     const output = await this.nativeModule.generate(
      |                                                    ^
  167 |       input,
  168 |       imageSize,
  169 |       numSteps,
Call Stack
  forward (packages/react-native-executorch/src/modules/computer_vision/TextToImageModule.ts:166:52)
  forward (packages/react-native-executorch/src/modules/computer_vision/TextToImageModule.ts:160:16)
  generate (packages/react-native-executorch/src/hooks/computer_vision/useTextToImage.ts:99:42)
  useTextToImage (packages/react-native-executorch/src/hooks/computer_vision/useTextToImage.ts:81:17)
  runForward (apps/computer-vision/app/text_to_image/index.tsx:56:42)
  TextToImageScreen (apps/computer-vision/app/text_to_image/index.tsx:50:19)
  TouchableOpacity.props.onPress (apps/computer-vision/components/BottomBarWithTextInput.tsx:85:21)

@chmjkb
Copy link
Collaborator Author

chmjkb commented Mar 13, 2026

I got an error when running text to image example:

 ERROR  [TypeError: this.nativeModule.generate is not a function (it is undefined)] 

Code: TextToImageModule.ts
  164 |     seed?: number
  165 |   ): Promise<string> {
> 166 |     const output = await this.nativeModule.generate(
      |                                                    ^
  167 |       input,
  168 |       imageSize,
  169 |       numSteps,
Call Stack
  forward (packages/react-native-executorch/src/modules/computer_vision/TextToImageModule.ts:166:52)
  forward (packages/react-native-executorch/src/modules/computer_vision/TextToImageModule.ts:160:16)
  generate (packages/react-native-executorch/src/hooks/computer_vision/useTextToImage.ts:99:42)
  useTextToImage (packages/react-native-executorch/src/hooks/computer_vision/useTextToImage.ts:81:17)
  runForward (apps/computer-vision/app/text_to_image/index.tsx:56:42)
  TextToImageScreen (apps/computer-vision/app/text_to_image/index.tsx:50:19)
  TouchableOpacity.props.onPress (apps/computer-vision/components/BottomBarWithTextInput.tsx:85:21)

Fixed in 27403e4

@msluszniak msluszniak self-requested a review March 13, 2026 11:17
@chmjkb chmjkb merged commit e827156 into main Mar 13, 2026
5 checks passed
@chmjkb chmjkb deleted the @chmjkb/static-factories-refactor branch March 13, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate existing model implementations to use factories instead of legacy flow

4 participants