diff --git a/apps/text-embeddings/android/app/src/main/AndroidManifest.xml b/apps/text-embeddings/android/app/src/main/AndroidManifest.xml index 5516f1955e..0c91cfdb3b 100644 --- a/apps/text-embeddings/android/app/src/main/AndroidManifest.xml +++ b/apps/text-embeddings/android/app/src/main/AndroidManifest.xml @@ -20,6 +20,12 @@ + + + + + + \ No newline at end of file diff --git a/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainActivity.kt b/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainActivity.kt index f27c511641..1d12e9a1fa 100644 --- a/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainActivity.kt +++ b/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainActivity.kt @@ -27,8 +27,8 @@ class MainActivity : ReactActivity() { * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] */ - override fun createReactActivityDelegate(): ReactActivityDelegate = - ReactActivityDelegateWrapper( + override fun createReactActivityDelegate(): ReactActivityDelegate { + return ReactActivityDelegateWrapper( this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, object : DefaultReactActivityDelegate( @@ -37,6 +37,7 @@ class MainActivity : ReactActivity() { fabricEnabled, ) {}, ) + } /** * Align the back button behavior with Android S diff --git a/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainApplication.kt b/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainApplication.kt index 3934ecb907..95020c01c2 100644 --- a/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainApplication.kt +++ b/apps/text-embeddings/android/app/src/main/java/com/anonymous/textembeddings/MainApplication.kt @@ -14,9 +14,7 @@ import com.facebook.soloader.SoLoader import expo.modules.ApplicationLifecycleDispatcher import expo.modules.ReactNativeHostWrapper -class MainApplication : - Application(), - ReactApplication { +class MainApplication : Application(), ReactApplication { override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper( this, @@ -24,7 +22,7 @@ class MainApplication : override fun getPackages(): List { val packages = PackageList(this).packages // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); + // packages.add(MyReactNativePackage()) return packages } diff --git a/apps/text-embeddings/app.json b/apps/text-embeddings/app.json index b7ba184dd0..ad2c0e140d 100644 --- a/apps/text-embeddings/app.json +++ b/apps/text-embeddings/app.json @@ -7,6 +7,7 @@ "icon": "./assets/icon.png", "userInterfaceStyle": "light", "newArchEnabled": true, + "scheme": "rne-embeddings", "splash": { "image": "./assets/splash-icon.png", "resizeMode": "contain", @@ -25,6 +26,7 @@ }, "web": { "favicon": "./assets/favicon.png" - } + }, + "plugins": ["expo-router"] } } diff --git a/apps/text-embeddings/app/_layout.tsx b/apps/text-embeddings/app/_layout.tsx new file mode 100644 index 0000000000..16bf0e87a3 --- /dev/null +++ b/apps/text-embeddings/app/_layout.tsx @@ -0,0 +1,101 @@ +import { Drawer } from 'expo-router/drawer'; +import ColorPalette from '../colors'; +import React, { useState } from 'react'; +import { Text, StyleSheet, View } from 'react-native'; + +import { + DrawerContentComponentProps, + DrawerContentScrollView, + DrawerItemList, +} from '@react-navigation/drawer'; +import { GeneratingContext } from '../context'; + +interface CustomDrawerProps extends DrawerContentComponentProps { + isGenerating: boolean; +} + +function CustomDrawerContent(props: CustomDrawerProps) { + const { isGenerating, ...otherProps } = props; + return ( + + {!isGenerating ? ( + + ) : ( + + Model is generating... + Interrupt before switching model + + )} + + ); +} + +export default function _layout() { + const [isGenerating, setIsGenerating] = useState(false); + + return ( + { + setIsGenerating(newState); + }, + }} + > + ( + + )} + screenOptions={{ + drawerActiveTintColor: ColorPalette.primary, + drawerInactiveTintColor: '#888', + headerTintColor: ColorPalette.primary, + headerTitleStyle: { color: ColorPalette.primary }, + }} + > + + + null, + title: 'Main Menu', + drawerItemStyle: { display: 'none' }, + }} + /> + + + ); +} + +const styles = StyleSheet.create({ + centerContent: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + padding: 20, + }, + mainText: { + fontSize: 18, + fontWeight: 'bold', + marginBottom: 10, + color: ColorPalette.primary, + }, + subText: { + fontSize: 14, + color: ColorPalette.strongPrimary, + }, +}); diff --git a/apps/text-embeddings/app/clip-embeddings/index.tsx b/apps/text-embeddings/app/clip-embeddings/index.tsx new file mode 100644 index 0000000000..ff99ccbbf3 --- /dev/null +++ b/apps/text-embeddings/app/clip-embeddings/index.tsx @@ -0,0 +1,388 @@ +import { useEffect, useState } from 'react'; +import { + StyleSheet, + Text, + TextInput, + TouchableOpacity, + View, + SafeAreaView, + ScrollView, + KeyboardAvoidingView, + Platform, +} from 'react-native'; +import { Ionicons } from '@expo/vector-icons'; +import { + useTextEmbeddings, + useImageEmbeddings, + CLIP_VIT_BASE_PATCH_32_TEXT_ENCODER, + CLIP_VIT_BASE_PATCH_32_IMAGE_ENCODER_MODEL, +} from 'react-native-executorch'; +import { launchImageLibrary } from 'react-native-image-picker'; +import { useIsFocused } from '@react-navigation/native'; + +export default function ClipEmbeddingsScreenWrapper() { + const isFocused = useIsFocused(); + + return isFocused ? : null; +} + +function ClipEmbeddingsScreen() { + const model = useTextEmbeddings({ + ...CLIP_VIT_BASE_PATCH_32_TEXT_ENCODER, + meanPooling: false, + }); + + const imageModel = useImageEmbeddings({ + modelSource: CLIP_VIT_BASE_PATCH_32_IMAGE_ENCODER_MODEL, + }); + + const [inputSentence, setInputSentence] = useState(''); + const [sentencesWithEmbeddings, setSentencesWithEmbeddings] = useState< + { sentence: string; embedding: number[] }[] + >([]); + const [topMatches, setTopMatches] = useState< + { sentence: string; similarity: number }[] + >([]); + + const dotProduct = (a: number[], b: number[]) => + a.reduce((sum, val, i) => sum + val * b[i], 0); + + useEffect( + () => { + const computeEmbeddings = async () => { + if (!model.isReady) return; + + const sentences = [ + 'The weather is lovely today.', + 'Night party pictures', + 'Cute animals.', + 'Bike club photos', + ]; + + try { + const embeddings = await Promise.all( + sentences.map(async (sentence) => ({ + sentence, + embedding: await model.forward(sentence), + })) + ); + + setSentencesWithEmbeddings(embeddings); + } catch (error) { + console.error('Error generating embeddings:', error); + } + }; + + computeEmbeddings(); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [model.isReady] + ); + + const checkSimilarities = async () => { + if (!model.isReady || !inputSentence.trim()) return; + + try { + const inputEmbedding = await model.forward(inputSentence); + const matches = sentencesWithEmbeddings.map( + ({ sentence, embedding }) => ({ + sentence, + similarity: dotProduct(inputEmbedding, embedding), + }) + ); + matches.sort((a, b) => b.similarity - a.similarity); + setTopMatches(matches.slice(0, 3)); + } catch (error) { + console.error('Error generating embedding:', error); + } + }; + + const addToSentences = async () => { + if (!model.isReady || !inputSentence.trim()) return; + + try { + const embedding = await model.forward(inputSentence); + setSentencesWithEmbeddings((prev) => [ + ...prev, + { sentence: inputSentence, embedding }, + ]); + } catch (error) { + console.error('Error generating embedding:', error); + } + + setInputSentence(''); + setTopMatches([]); + }; + + const clearList = async () => { + if (!model.isReady) return; + try { + setSentencesWithEmbeddings([]); + } catch (error) { + console.error('Error clearing the list:', error); + } + }; + const checkImage = async () => { + if (!imageModel.isReady) return; + + const output = await launchImageLibrary({ mediaType: 'photo' }); + + if (!output.assets || output.assets.length === 0 || !output.assets[0].uri) + return; + + try { + // Array.from to get numbers[] + const inputImageEmbedding = Array.from( + await imageModel.forward(output.assets[0].uri) + ); + + const matches = sentencesWithEmbeddings.map( + ({ sentence, embedding }) => ({ + sentence, + similarity: dotProduct(inputImageEmbedding, embedding), + }) + ); + matches.sort((a, b) => b.similarity - a.similarity); + setTopMatches(matches.slice(0, 3)); + } catch (error) { + console.error('Error generating embedding:', error); + } + }; + + const getModelStatusText = () => { + if (model.error || imageModel.error) { + return `Oops! Error: ${model.error || imageModel.error}`; + } + if (!model.isReady || !imageModel.isReady) { + return `Loading model ${(((model.downloadProgress + imageModel.downloadProgress) / 2) * 100).toFixed(2)}%`; + } + return model.isGenerating || imageModel.isGenerating + ? 'Generating...' + : 'Model is ready'; + }; + + return ( + + + + Text Embeddings Playground + {getModelStatusText()} + + + List of Existing Sentences + {sentencesWithEmbeddings.map((item, index) => ( + + - {item.sentence} + + ))} + + + Try Your Sentence + + + + + + Find Similar + + + + + + + Add to List + + + + + Compare sentences to image + + + + + + Clear List + + + + + {topMatches.length > 0 && ( + + Top Matches + {topMatches.map((item, index) => ( + + {item.sentence} ({item.similarity.toFixed(2)}) + + ))} + + )} + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#F8FAFC', + }, + scrollContainer: { + padding: 20, + alignItems: 'center', + flexGrow: 1, + }, + heading: { + fontSize: 24, + fontWeight: '500', + marginBottom: 20, + color: '#0F172A', + }, + card: { + backgroundColor: '#FFFFFF', + width: '100%', + padding: 16, + borderRadius: 16, + borderColor: '#E2E8F0', + borderWidth: 2, + marginBottom: 20, + }, + sectionTitle: { + fontSize: 18, + fontWeight: '500', + marginBottom: 12, + color: '#1E293B', + }, + sentenceText: { + fontSize: 14, + marginBottom: 6, + color: '#334155', + }, + input: { + backgroundColor: '#F1F5F9', + borderRadius: 10, + padding: 10, + marginBottom: 10, + fontSize: 16, + color: '#0F172A', + minHeight: 40, + textAlignVertical: 'top', + }, + buttonContainer: { + width: '100%', + gap: 10, + }, + buttonGroup: { + flexDirection: 'row', + justifyContent: 'space-between', + gap: 10, + }, + buttonPrimary: { + flex: 1, + backgroundColor: 'navy', + padding: 12, + borderRadius: 10, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + buttonSecondary: { + flex: 1, + backgroundColor: 'transparent', + borderWidth: 2, + borderColor: 'navy', + padding: 12, + borderRadius: 10, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + buttonDisabled: { + backgroundColor: '#f0f0f0', + borderColor: '#d3d3d3', + }, + buttonText: { + color: 'white', + textAlign: 'center', + fontWeight: '500', + }, + buttonTextOutline: { + color: 'navy', + textAlign: 'center', + fontWeight: '500', + }, + buttonTextDisabled: { + color: 'gray', + }, + topMatchesContainer: { + marginTop: 20, + }, + flexContainer: { + flex: 1, + }, +}); diff --git a/apps/text-embeddings/app/index.tsx b/apps/text-embeddings/app/index.tsx new file mode 100644 index 0000000000..f661e44978 --- /dev/null +++ b/apps/text-embeddings/app/index.tsx @@ -0,0 +1,69 @@ +import { useRouter } from 'expo-router'; +import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; +import ColorPalette from '../colors'; +import ExecutorchLogo from '../assets/executorch.svg'; + +export default function Home() { + const router = useRouter(); + + return ( + + + Select a demo model + + router.navigate('text-embeddings/')} + > + Text embeddings + + router.navigate('clip-embeddings/')} + > + Clip embeddings + + + + ); +} + +export const fontSizes = { + xxl: 34, + xl: 22, + lg: 18, + md: 16, + sm: 14, + xs: 12, + xxs: 10, +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#fff', + }, + headerText: { + fontSize: fontSizes.lg, + color: ColorPalette.strongPrimary, + margin: 20, + }, + buttonContainer: { + width: '80%', + justifyContent: 'space-evenly', + marginBottom: 20, + }, + button: { + backgroundColor: ColorPalette.strongPrimary, + borderRadius: 8, + padding: 10, + alignItems: 'center', + marginBottom: 10, + }, + buttonText: { + color: 'white', + fontSize: fontSizes.md, + }, +}); diff --git a/apps/text-embeddings/App.tsx b/apps/text-embeddings/app/text-embeddings/index.tsx similarity index 97% rename from apps/text-embeddings/App.tsx rename to apps/text-embeddings/app/text-embeddings/index.tsx index 2b9cf92043..0e8be19b1e 100644 --- a/apps/text-embeddings/App.tsx +++ b/apps/text-embeddings/app/text-embeddings/index.tsx @@ -16,11 +16,19 @@ import { ALL_MINILM_L6_V2, ALL_MINILM_L6_V2_TOKENIZER, } from 'react-native-executorch'; +import { useIsFocused } from '@react-navigation/native'; -export default function App() { +export default function TextEmbeddingsScreenWrapper() { + const isFocused = useIsFocused(); + + return isFocused ? : null; +} + +function TextEmbeddingsScreen() { const model = useTextEmbeddings({ modelSource: ALL_MINILM_L6_V2, tokenizerSource: ALL_MINILM_L6_V2_TOKENIZER, + meanPooling: true, }); const [inputSentence, setInputSentence] = useState(''); @@ -108,6 +116,7 @@ export default function App() { console.error('Error clearing the list:', error); } }; + const getModelStatusText = () => { if (model.error) { return `Oops! Error: ${model.error}`; diff --git a/apps/text-embeddings/assets/executorch.svg b/apps/text-embeddings/assets/executorch.svg new file mode 100644 index 0000000000..e548ea4201 --- /dev/null +++ b/apps/text-embeddings/assets/executorch.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/text-embeddings/babel.config.js b/apps/text-embeddings/babel.config.js new file mode 100644 index 0000000000..9d89e13119 --- /dev/null +++ b/apps/text-embeddings/babel.config.js @@ -0,0 +1,6 @@ +module.exports = function (api) { + api.cache(true); + return { + presets: ['babel-preset-expo'], + }; +}; diff --git a/apps/text-embeddings/colors.ts b/apps/text-embeddings/colors.ts new file mode 100644 index 0000000000..03defcda9e --- /dev/null +++ b/apps/text-embeddings/colors.ts @@ -0,0 +1,11 @@ +const ColorPalette = { + primary: '#001A72', + seaBlueLight: '#E1F3FA', + seaBlueMedium: '#B5E1F1', + seaBlueDark: '#87CCE8', + blueLight: '#C1C6E5', + blueDark: '#6676AA', + strongPrimary: '#020F3C', +}; + +export default ColorPalette; diff --git a/apps/text-embeddings/context.ts b/apps/text-embeddings/context.ts new file mode 100644 index 0000000000..0eb0560768 --- /dev/null +++ b/apps/text-embeddings/context.ts @@ -0,0 +1,5 @@ +import { createContext } from 'react'; + +export const GeneratingContext = createContext({ + setGlobalGenerating: (_newState: boolean) => {}, +}); diff --git a/apps/text-embeddings/declarations.d.ts b/apps/text-embeddings/declarations.d.ts new file mode 100644 index 0000000000..85e178f497 --- /dev/null +++ b/apps/text-embeddings/declarations.d.ts @@ -0,0 +1,5 @@ +declare module '*.svg' { + import { SvgProps } from 'react-native-svg'; + const content: React.FV; + export default content; +} diff --git a/apps/text-embeddings/index.ts b/apps/text-embeddings/index.ts index 1d6e981ef6..3f443dcf95 100644 --- a/apps/text-embeddings/index.ts +++ b/apps/text-embeddings/index.ts @@ -1,6 +1,6 @@ import { registerRootComponent } from 'expo'; -import App from './App'; +import App from './app'; // registerRootComponent calls AppRegistry.registerComponent('main', () => App); // It also ensures that whether you load the app in Expo Go or in a native build, diff --git a/apps/text-embeddings/ios/Podfile.lock b/apps/text-embeddings/ios/Podfile.lock index 9b0f78236b..d581edb5f8 100644 --- a/apps/text-embeddings/ios/Podfile.lock +++ b/apps/text-embeddings/ios/Podfile.lock @@ -36,8 +36,12 @@ PODS: - ExpoModulesCore - ExpoFont (13.3.1): - ExpoModulesCore + - ExpoHead (5.1.0): + - ExpoModulesCore - ExpoKeepAwake (14.1.4): - ExpoModulesCore + - ExpoLinking (7.1.5): + - ExpoModulesCore - ExpoModulesCore (2.4.0): - DoubleConversion - glog @@ -1421,6 +1425,105 @@ PODS: - ReactCommon/turbomodule/core - sqlite3 - Yoga + - react-native-image-picker (7.2.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context (5.4.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common (= 5.4.0) + - react-native-safe-area-context/fabric (= 5.4.0) + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/common (5.4.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/fabric (5.4.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - React-NativeModulesApple (0.79.2): - glog - hermes-engine @@ -1743,6 +1846,254 @@ PODS: - React-logger (= 0.79.2) - React-perflogger (= 0.79.2) - React-utils (= 0.79.2) + - RNGestureHandler (2.24.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNReanimated (3.17.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNReanimated/reanimated (= 3.17.5) + - RNReanimated/worklets (= 3.17.5) + - Yoga + - RNReanimated/reanimated (3.17.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNReanimated/reanimated/apple (= 3.17.5) + - Yoga + - RNReanimated/reanimated/apple (3.17.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNReanimated/worklets (3.17.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNReanimated/worklets/apple (= 3.17.5) + - Yoga + - RNReanimated/worklets/apple (3.17.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNScreens (4.11.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNScreens/common (= 4.11.1) + - Yoga + - RNScreens/common (4.11.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNSVG (15.11.2): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNSVG/common (= 15.11.2) + - Yoga + - RNSVG/common (15.11.2): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - SocketRocket (0.7.1) - sqlite3 (3.50.1): - sqlite3/common (= 3.50.1) @@ -1757,7 +2108,9 @@ DEPENDENCIES: - ExpoAsset (from `../../../node_modules/expo-asset/ios`) - ExpoFileSystem (from `../../../node_modules/expo-file-system/ios`) - ExpoFont (from `../../../node_modules/expo-font/ios`) + - ExpoHead (from `../node_modules/expo-router/ios`) - ExpoKeepAwake (from `../../../node_modules/expo-keep-awake/ios`) + - ExpoLinking (from `../../../node_modules/expo-linking/ios`) - ExpoModulesCore (from `../../../node_modules/expo-modules-core`) - fast_float (from `../../../node_modules/react-native/third-party-podspecs/fast_float.podspec`) - FBLazyVector (from `../../../node_modules/react-native/Libraries/FBLazyVector`) @@ -1798,6 +2151,8 @@ DEPENDENCIES: - React-Mapbuffer (from `../../../node_modules/react-native/ReactCommon`) - React-microtasksnativemodule (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) - react-native-executorch (from `../../../node_modules/react-native-executorch`) + - react-native-image-picker (from `../../../node_modules/react-native-image-picker`) + - react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`) - React-NativeModulesApple (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-oscompat (from `../../../node_modules/react-native/ReactCommon/oscompat`) - React-perflogger (from `../../../node_modules/react-native/ReactCommon/reactperflogger`) @@ -1829,6 +2184,10 @@ DEPENDENCIES: - ReactAppDependencyProvider (from `build/generated/ios`) - ReactCodegen (from `build/generated/ios`) - ReactCommon/turbomodule/core (from `../../../node_modules/react-native/ReactCommon`) + - RNGestureHandler (from `../../../node_modules/react-native-gesture-handler`) + - RNReanimated (from `../../../node_modules/react-native-reanimated`) + - RNScreens (from `../../../node_modules/react-native-screens`) + - RNSVG (from `../../../node_modules/react-native-svg`) - Yoga (from `../../../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: @@ -1852,8 +2211,12 @@ EXTERNAL SOURCES: :path: "../../../node_modules/expo-file-system/ios" ExpoFont: :path: "../../../node_modules/expo-font/ios" + ExpoHead: + :path: "../node_modules/expo-router/ios" ExpoKeepAwake: :path: "../../../node_modules/expo-keep-awake/ios" + ExpoLinking: + :path: "../../../node_modules/expo-linking/ios" ExpoModulesCore: :path: "../../../node_modules/expo-modules-core" fast_float: @@ -1931,6 +2294,10 @@ EXTERNAL SOURCES: :path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" react-native-executorch: :path: "../../../node_modules/react-native-executorch" + react-native-image-picker: + :path: "../../../node_modules/react-native-image-picker" + react-native-safe-area-context: + :path: "../../../node_modules/react-native-safe-area-context" React-NativeModulesApple: :path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" React-oscompat: @@ -1993,91 +2360,107 @@ EXTERNAL SOURCES: :path: build/generated/ios ReactCommon: :path: "../../../node_modules/react-native/ReactCommon" + RNGestureHandler: + :path: "../../../node_modules/react-native-gesture-handler" + RNReanimated: + :path: "../../../node_modules/react-native-reanimated" + RNScreens: + :path: "../../../node_modules/react-native-screens" + RNSVG: + :path: "../../../node_modules/react-native-svg" Yoga: :path: "../../../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb - EXConstants: 9f310f44bfedba09087042756802040e464323c0 - Expo: 4e8bda07d30b024b1732f87843a5349a3ecc1316 - ExpoAsset: 3bc9adb7dbbf27ae82c18ca97eb988a3ae7e73b1 - ExpoFileSystem: c36eb8155eb2381c83dda7dc210e3eec332368b6 - ExpoFont: abbb91a911eb961652c2b0a22eef801860425ed6 - ExpoKeepAwake: bf0811570c8da182bfb879169437d4de298376e7 - ExpoModulesCore: d431ffe83c8673d02cb38425594a5f5480fd3061 + EXConstants: be238322d57d084dc055dbd5d6fe6479510504ce + Expo: 77b39f42396989cbe6fbef9f6fafc9b35186a95b + ExpoAsset: 3ea3275cca6a7793b3d36fbf1075c590f803fbcb + ExpoFileSystem: 3a98ca2a6f13674ecfd97327d1b44a8ace444cbd + ExpoFont: 312c73403bbd4f98e1d6a5330641a56292583cd2 + ExpoHead: 777572a222b83d81c1f9aa6fb20e8fc0a80f851f + ExpoKeepAwake: e8dedc115d9f6f24b153ccd2d1d8efcdfd68a527 + ExpoLinking: 5d151d4a497d7e375308602f0a89b4e8acf7b5f8 + ExpoModulesCore: e2e363bcdee87b46f858586d1887ebb215582001 fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6 FBLazyVector: 84b955f7b4da8b895faf5946f73748267347c975 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: 314be5250afa5692b57b4dd1705959e1973a8ebe opencv-rne: 2305807573b6e29c8c87e3416ab096d09047a7a0 - RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 + RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809 RCTDeprecation: 83ffb90c23ee5cea353bd32008a7bca100908f8c RCTRequired: eb7c0aba998009f47a540bec9e9d69a54f68136e RCTTypeSafety: 659ae318c09de0477fd27bbc9e140071c7ea5c93 React: c2d3aa44c49bb34e4dfd49d3ee92da5ebacc1c1c React-callinvoker: 1bdfb7549b5af266d85757193b5069f60659ef9d - React-Core: 10597593fdbae06f0089881e025a172e51d4a769 - React-CoreModules: 6907b255529dd46895cf687daa67b24484a612c2 - React-cxxreact: a9f5b8180d6955bc3f6a3fcd657c4d9b4d95c1f6 + React-Core: 7150cf9b6a5af063b37003062689f1691e79c020 + React-CoreModules: 15a85e6665d61678942da6ae485b351f4c699049 + React-cxxreact: 74f9de59259ac951923f5726aa14f0398f167af9 React-debug: e74e76912b91e08d580c481c34881899ccf63da9 - React-defaultsnativemodule: 11f6ee2cf69bf3af9d0f28a6253def33d21b5266 - React-domnativemodule: f940bbc4fa9e134190acbf3a4a9f95621b5a8f51 - React-Fabric: 6f5c357bf3a42ff11f8844ad3fc7a1eb04f4b9de - React-FabricComponents: 10e0c0209822ac9e69412913a8af1ca33573379b - React-FabricImage: f582e764072dfa4715ae8c42979a5bace9cbcc12 + React-defaultsnativemodule: 628285212bbd65417d40ad6a9f8781830fda6c98 + React-domnativemodule: 185d9808198405c176784aaf33403d713bd24fb7 + React-Fabric: c814804affbe1952e16149ddd20256e1bccae67e + React-FabricComponents: 81ef47d596966121784afec9924f9562a29b1691 + React-FabricImage: f14f371d678aa557101def954ac3ba27e48948ff React-featureflags: d5facceff8f8f6de430e0acecf4979a9a0839ba9 - React-featureflagsnativemodule: a7dd141f1ef4b7c1331af0035689fbc742a49ff4 - React-graphics: 36ae3407172c1c77cea29265d2b12b90aaef6aa0 - React-hermes: 9116d4e6d07abeb519a2852672de087f44da8f12 - React-idlecallbacksnativemodule: ae7f5ffc6cf2d2058b007b78248e5b08172ad5c3 - React-ImageManager: 9daee0dc99ad6a001d4b9e691fbf37107e2b7b54 - React-jserrorhandler: 1e6211581071edaf4ecd5303147328120c73f4dc - React-jsi: 753ba30c902f3a41fa7f956aca8eea3317a44ee6 - React-jsiexecutor: 47520714aa7d9589c51c0f3713dfbfca4895d4f9 - React-jsinspector: cfd27107f6d6f1076a57d88c932401251560fe5f - React-jsinspectortracing: 76a7d791f3c0c09a0d2bf6f46dfb0e79a4fcc0ac - React-jsitooling: 995e826570dd58f802251490486ebd3244a037ab - React-jsitracing: 094ae3d8c123cea67b50211c945b7c0443d3e97b - React-logger: 8edfcedc100544791cd82692ca5a574240a16219 - React-Mapbuffer: c3f4b608e4a59dd2f6a416ef4d47a14400194468 - React-microtasksnativemodule: 054f34e9b82f02bd40f09cebd4083828b5b2beb6 - react-native-executorch: 9e4c26039a419f8b79c040571e80617c1114ca26 - React-NativeModulesApple: 2c4377e139522c3d73f5df582e4f051a838ff25e + React-featureflagsnativemodule: 96f0ab285382d95c90f663e02526a5ceefa95a11 + React-graphics: 1a66ee0a3f093b125b853f6370296fadcaf6f233 + React-hermes: 8b86e5f54a65ecb69cdf22b3a00a11562eda82d2 + React-idlecallbacksnativemodule: 5c25ab145c602264d00cb26a397ab52e0efa031c + React-ImageManager: 15e34bd5ef1ac4a18e96660817ef70a7f99ee8c2 + React-jserrorhandler: 02cdf2cd45350108be1ffd2b164578936dbbdff7 + React-jsi: 6af1987cfbb1b6621664fdbf6c7b62bd4d38c923 + React-jsiexecutor: 51f372998e0303585cb0317232b938d694663cbd + React-jsinspector: 3539ad976d073bfaa8a7d2fa9bef35e70e55033e + React-jsinspectortracing: e8dbacaf67c201f23052ca1c2bae2f7b84dec443 + React-jsitooling: 95a34f41e3c249d42181de13b4f8d854f178ca9f + React-jsitracing: 25b029cf5cad488252d46da19dd8c4c134fd5fe4 + React-logger: 368570a253f00879a1e4fea24ed4047e72e7bbf3 + React-Mapbuffer: c04fcda1c6281fc0a6824c7dcc1633dd217ac1ec + React-microtasksnativemodule: ca2804a25fdcefffa0aa942aa23ab53b99614a34 + react-native-executorch: 66ffc33df70ec85bc591f9ee34c862835966ead3 + react-native-image-picker: 2d194850656e2eb5aaefe9c25c0ba926b44cf6a6 + react-native-safe-area-context: 00d03dc688ba86664be66f9e3f203fc7d747d899 + React-NativeModulesApple: 452b86b29fae99ed0a4015dca3ad9cd222f88abf React-oscompat: ef5df1c734f19b8003e149317d041b8ce1f7d29c - React-perflogger: 9a151e0b4c933c9205fd648c246506a83f31395d - React-performancetimeline: 5b0dfc0acba29ea0269ddb34cd6dd59d3b8a1c66 + React-perflogger: 6fd2f6811533e9c19a61e855c3033eecbf4ad2a0 + React-performancetimeline: abf31259d794c9274b3ea19c5016186925eec6c4 React-RCTActionSheet: a499b0d6d9793886b67ba3e16046a3fef2cdbbc3 - React-RCTAnimation: cc64adc259aabc3354b73065e2231d796dfce576 - React-RCTAppDelegate: 9d523da768f1c9e84c5f3b7e3624d097dfb0e16b - React-RCTBlob: e727f53eeefded7e6432eb76bd22b57bc880e5d1 - React-RCTFabric: 58590aa4fdb4ad546c06a7449b486cf6844e991f - React-RCTFBReactNativeSpec: 9064c63d99e467a3893e328ba3612745c3c3a338 - React-RCTImage: 7159cbdbb18a09d97ba1a611416eced75b3ccb29 - React-RCTLinking: 46293afdb859bccc63e1d3dedc6901a3c04ef360 - React-RCTNetwork: 4a6cd18f5bcd0363657789c64043123a896b1170 - React-RCTRuntime: 5ab904fd749aa52f267ef771d265612582a17880 - React-RCTSettings: 61e361dc85136d1cb0e148b7541993d2ee950ea7 - React-RCTText: abd1e196c3167175e6baef18199c6d9d8ac54b4e - React-RCTVibration: 490e0dcb01a3fe4a0dfb7bc51ad5856d8b84f343 + React-RCTAnimation: 2595dcb10a82216a511b54742f8c28d793852ac6 + React-RCTAppDelegate: f03604b70f57c9469a84a159d8abecf793a5bcff + React-RCTBlob: e00f9b4e2f151938f4d9864cf33ebf24ac03328a + React-RCTFabric: 3945d116fd271598db262d4e6ed5691d431ed9e8 + React-RCTFBReactNativeSpec: 0f4d4f0da938101f2ca9d5333a8f46e527ad2819 + React-RCTImage: dac5e9f8ec476aefe6e60ee640ebc1dfaf1a4dbe + React-RCTLinking: 494b785a40d952a1dfbe712f43214376e5f0e408 + React-RCTNetwork: b3d7c30cd21793e268db107dd0980cb61b3c1c44 + React-RCTRuntime: a8ff419d437228e7b8a793b14f9d711e1cbb82af + React-RCTSettings: a060c7e381a3896104761b8eed7e284d95e37df3 + React-RCTText: 4f272b72dbb61f390d8c8274528f9fdbff983806 + React-RCTVibration: 0e5326220719aca12473d703aa46693e3b4ce67a React-rendererconsistency: 351fdbc5c1fe4da24243d939094a80f0e149c7a1 - React-renderercss: 3438814bee838ae7840a633ab085ac81699fd5cf - React-rendererdebug: 0ac2b9419ad6f88444f066d4b476180af311fb1e + React-renderercss: d333f2ada83969591100d91ec6b23ca2e17e1507 + React-rendererdebug: 039e5949b72ba63c703de020701e3fd152434c61 React-rncore: 57ed480649bb678d8bdc386d20fee8bf2b0c307c - React-RuntimeApple: 8b7a9788f31548298ba1990620fe06b40de65ad7 - React-RuntimeCore: e03d96fbd57ce69fd9bca8c925942194a5126dbc + React-RuntimeApple: 344a5e1105256000afabaa8df12c3e4cab880340 + React-RuntimeCore: 0e48fb5e5160acc0334c7a723a42d42cef4b58b6 React-runtimeexecutor: d60846710facedd1edb70c08b738119b3ee2c6c2 - React-RuntimeHermes: aab794755d9f6efd249b61f3af4417296904e3ba - React-runtimescheduler: c3cd124fa5db7c37f601ee49ca0d97019acd8788 + React-RuntimeHermes: 064286a03871d932c99738e0f8ef854962ab4b99 + React-runtimescheduler: e917ab17ae08c204af1ebf8f669b7e411b0220c8 React-timing: a90f4654cbda9c628614f9bee68967f1768bd6a5 - React-utils: a612d50555b6f0f90c74b7d79954019ad47f5de6 - ReactAppDependencyProvider: 04d5eb15eb46be6720e17a4a7fa92940a776e584 - ReactCodegen: 7ea266ccd94436294f516247db7402b57b1214af - ReactCommon: 76d2dc87136d0a667678668b86f0fca0c16fdeb0 + React-utils: 51c4e71608b8133fecc9a15801d244ae7bdf3758 + ReactAppDependencyProvider: d5dcc564f129632276bd3184e60f053fcd574d6b + ReactCodegen: c9a256facbe4996140f3fb95c7f03ba61c12acc9 + ReactCommon: 4d0da92a5eb8da86c08e3ec34bd23ab439fb2461 + RNGestureHandler: ccf4105b125002bd88e39d2a1f2b7e6001bcdf34 + RNReanimated: c567de23384730756bb19ff55490819980536b09 + RNScreens: c2e3cc506212228c607b4785b315205e28acbf0f + RNSVG: ee32efbed652c5151fd3f98bed13c68af285bc38 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 sqlite3: 1d85290c3321153511f6e900ede7a1608718bbd5 - Yoga: c758bfb934100bb4bf9cbaccb52557cee35e8bdf + Yoga: 9f110fc4b7aa538663cba3c14cbb1c335f43c13f PODFILE CHECKSUM: a4eba0f176efffd0a3e176573036da7710a6c813 diff --git a/apps/text-embeddings/ios/textembeddings.xcodeproj/project.pbxproj b/apps/text-embeddings/ios/textembeddings.xcodeproj/project.pbxproj index 7ddd48309e..031014082c 100644 --- a/apps/text-embeddings/ios/textembeddings.xcodeproj/project.pbxproj +++ b/apps/text-embeddings/ios/textembeddings.xcodeproj/project.pbxproj @@ -8,28 +8,28 @@ /* Begin PBXBuildFile section */ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 1ED5A1EE5B60B6C7258DF042 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09277D877A7B7CCB2BDB967E /* ExpoModulesProvider.swift */; }; 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; }; - 5B13B591D04D9BA31EF49189 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4F3E837FCA8D8DE8D5A5B9C9 /* PrivacyInfo.xcprivacy */; }; - 5F80B9C936EED7FA2D06AEEA /* libPods-textembeddings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 48AED609434A8B9B37BDF053 /* libPods-textembeddings.a */; }; + 423851AEE84BAD816B6046E7 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = F7EAE72418BE4572CA312779 /* PrivacyInfo.xcprivacy */; }; BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; + D64A9AD0FB5184536527C472 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C43A127F997A1C23D30F1EF /* ExpoModulesProvider.swift */; }; F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; }; + F222E4E35B026ADF0826F0B8 /* libPods-textembeddings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 759874E9EC6FEEE06724753E /* libPods-textembeddings.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 06AA54A47479F9CA5CC4D0B9 /* Pods-textembeddings.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-textembeddings.release.xcconfig"; path = "Target Support Files/Pods-textembeddings/Pods-textembeddings.release.xcconfig"; sourceTree = ""; }; - 09277D877A7B7CCB2BDB967E /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-textembeddings/ExpoModulesProvider.swift"; sourceTree = ""; }; + 0C43A127F997A1C23D30F1EF /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-textembeddings/ExpoModulesProvider.swift"; sourceTree = ""; }; + 0D7E1D2EAE3117E578B540F5 /* Pods-textembeddings.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-textembeddings.debug.xcconfig"; path = "Target Support Files/Pods-textembeddings/Pods-textembeddings.debug.xcconfig"; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* textembeddings.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = textembeddings.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = textembeddings/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = textembeddings/Info.plist; sourceTree = ""; }; - 27E69F62B49ACB38F977A96E /* Pods-textembeddings.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-textembeddings.debug.xcconfig"; path = "Target Support Files/Pods-textembeddings/Pods-textembeddings.debug.xcconfig"; sourceTree = ""; }; - 48AED609434A8B9B37BDF053 /* libPods-textembeddings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-textembeddings.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 4F3E837FCA8D8DE8D5A5B9C9 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = textembeddings/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 759874E9EC6FEEE06724753E /* libPods-textembeddings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-textembeddings.a"; sourceTree = BUILT_PRODUCTS_DIR; }; AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = textembeddings/SplashScreen.storyboard; sourceTree = ""; }; BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + EE1DB44C2E5262491D8BAB50 /* Pods-textembeddings.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-textembeddings.release.xcconfig"; path = "Target Support Files/Pods-textembeddings/Pods-textembeddings.release.xcconfig"; sourceTree = ""; }; F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = textembeddings/AppDelegate.swift; sourceTree = ""; }; F11748442D0722820044C1D9 /* textembeddings-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "textembeddings-Bridging-Header.h"; path = "textembeddings/textembeddings-Bridging-Header.h"; sourceTree = ""; }; + F7EAE72418BE4572CA312779 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = textembeddings/PrivacyInfo.xcprivacy; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -37,21 +37,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5F80B9C936EED7FA2D06AEEA /* libPods-textembeddings.a in Frameworks */, + F222E4E35B026ADF0826F0B8 /* libPods-textembeddings.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 0F3A6A2176AA50897F94C4F4 /* textembeddings */ = { - isa = PBXGroup; - children = ( - 09277D877A7B7CCB2BDB967E /* ExpoModulesProvider.swift */, - ); - name = textembeddings; - sourceTree = ""; - }; 13B07FAE1A68108700A75B9A /* textembeddings */ = { isa = PBXGroup; children = ( @@ -61,7 +53,7 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */, 13B07FB61A68108700A75B9A /* Info.plist */, AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */, - 4F3E837FCA8D8DE8D5A5B9C9 /* PrivacyInfo.xcprivacy */, + F7EAE72418BE4572CA312779 /* PrivacyInfo.xcprivacy */, ); name = textembeddings; sourceTree = ""; @@ -70,29 +62,21 @@ isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 48AED609434A8B9B37BDF053 /* libPods-textembeddings.a */, + 759874E9EC6FEEE06724753E /* libPods-textembeddings.a */, ); name = Frameworks; sourceTree = ""; }; - 52041C0C85DB673AEA4A5279 /* Pods */ = { + 62F20DBF5BDAA2BCBF024EAE /* Pods */ = { isa = PBXGroup; children = ( - 27E69F62B49ACB38F977A96E /* Pods-textembeddings.debug.xcconfig */, - 06AA54A47479F9CA5CC4D0B9 /* Pods-textembeddings.release.xcconfig */, + 0D7E1D2EAE3117E578B540F5 /* Pods-textembeddings.debug.xcconfig */, + EE1DB44C2E5262491D8BAB50 /* Pods-textembeddings.release.xcconfig */, ); name = Pods; path = Pods; sourceTree = ""; }; - 8116C29C6CC4059B4719A367 /* ExpoModulesProviders */ = { - isa = PBXGroup; - children = ( - 0F3A6A2176AA50897F94C4F4 /* textembeddings */, - ); - name = ExpoModulesProviders; - sourceTree = ""; - }; 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( @@ -107,8 +91,8 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */, 83CBBA001A601CBA00E9B192 /* Products */, 2D16E6871FA4F8E400B85C8A /* Frameworks */, - 52041C0C85DB673AEA4A5279 /* Pods */, - 8116C29C6CC4059B4719A367 /* ExpoModulesProviders */, + 62F20DBF5BDAA2BCBF024EAE /* Pods */, + E6FB4A14185948A4037182E5 /* ExpoModulesProviders */, ); indentWidth = 2; sourceTree = ""; @@ -123,6 +107,14 @@ name = Products; sourceTree = ""; }; + A012DC1FEDCF1C9E47C1EA99 /* textembeddings */ = { + isa = PBXGroup; + children = ( + 0C43A127F997A1C23D30F1EF /* ExpoModulesProvider.swift */, + ); + name = textembeddings; + sourceTree = ""; + }; BB2F792B24A3F905000567C9 /* Supporting */ = { isa = PBXGroup; children = ( @@ -132,6 +124,14 @@ path = textembeddings/Supporting; sourceTree = ""; }; + E6FB4A14185948A4037182E5 /* ExpoModulesProviders */ = { + isa = PBXGroup; + children = ( + A012DC1FEDCF1C9E47C1EA99 /* textembeddings */, + ); + name = ExpoModulesProviders; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -140,13 +140,13 @@ buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "textembeddings" */; buildPhases = ( 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */, - 0147E749E0E0C5817BA453DA /* [Expo] Configure project */, + 83193180A3529D0FBA7F9B58 /* [Expo] Configure project */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */, - 9709100C3F5005A3BF158FCC /* [CP] Embed Pods Frameworks */, + 5847ECD7D6EB70E0BC623DB7 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -167,6 +167,8 @@ TargetAttributes = { 13B07F861A680F5B00A75B9A = { LastSwiftMigration = 1250; + DevelopmentTeam = "HK2467NFN5"; + ProvisioningStyle = Automatic; }; }; }; @@ -196,7 +198,7 @@ BB2F792D24A3F905000567C9 /* Expo.plist in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */, - 5B13B591D04D9BA31EF49189 /* PrivacyInfo.xcprivacy in Resources */, + 423851AEE84BAD816B6046E7 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -218,45 +220,46 @@ shellPath = /bin/sh; shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n"; }; - 0147E749E0E0C5817BA453DA /* [Expo] Configure project */ = { + 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = "[Expo] Configure project"; + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-textembeddings-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-textembeddings/expo-configure-project.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = { + 5847ECD7D6EB70E0BC623DB7 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-textembeddings/Pods-textembeddings-frameworks.sh", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/react-native-executorch/ExecutorchLib.framework/ExecutorchLib", ); + name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-textembeddings-checkManifestLockResult.txt", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExecutorchLib.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-textembeddings/Pods-textembeddings-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = { @@ -270,10 +273,12 @@ "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/react-native-image-picker/RNImagePickerPrivacyInfo.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( @@ -281,35 +286,36 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNImagePickerPrivacyInfo.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-textembeddings/Pods-textembeddings-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 9709100C3F5005A3BF158FCC /* [CP] Embed Pods Frameworks */ = { + 83193180A3529D0FBA7F9B58 /* [Expo] Configure project */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-textembeddings/Pods-textembeddings-frameworks.sh", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/react-native-executorch/ExecutorchLib.framework/ExecutorchLib", ); - name = "[CP] Embed Pods Frameworks"; + name = "[Expo] Configure project"; + outputFileListPaths = ( + ); outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExecutorchLib.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-textembeddings/Pods-textembeddings-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-textembeddings/expo-configure-project.sh\"\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -319,7 +325,7 @@ buildActionMask = 2147483647; files = ( F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */, - 1ED5A1EE5B60B6C7258DF042 /* ExpoModulesProvider.swift in Sources */, + D64A9AD0FB5184536527C472 /* ExpoModulesProvider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -328,7 +334,7 @@ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 27E69F62B49ACB38F977A96E /* Pods-textembeddings.debug.xcconfig */; + baseConfigurationReference = 0D7E1D2EAE3117E578B540F5 /* Pods-textembeddings.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -359,12 +365,15 @@ SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; + DEVELOPMENT_TEAM = "HK2467NFN5"; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; }; name = Debug; }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 06AA54A47479F9CA5CC4D0B9 /* Pods-textembeddings.release.xcconfig */; + baseConfigurationReference = EE1DB44C2E5262491D8BAB50 /* Pods-textembeddings.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -389,6 +398,9 @@ SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; + DEVELOPMENT_TEAM = "HK2467NFN5"; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; }; name = Release; }; diff --git a/apps/text-embeddings/ios/textembeddings/Info.plist b/apps/text-embeddings/ios/textembeddings/Info.plist index 45dd291393..9397b49e44 100644 --- a/apps/text-embeddings/ios/textembeddings/Info.plist +++ b/apps/text-embeddings/ios/textembeddings/Info.plist @@ -27,6 +27,7 @@ CFBundleURLSchemes + rne-embeddings com.anonymous.text-embeddings @@ -44,6 +45,10 @@ NSAllowsLocalNetworking + NSUserActivityTypes + + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + UILaunchStoryboardName SplashScreen UIRequiredDeviceCapabilities diff --git a/apps/text-embeddings/metro.config.js b/apps/text-embeddings/metro.config.js new file mode 100644 index 0000000000..f8ab2ab96d --- /dev/null +++ b/apps/text-embeddings/metro.config.js @@ -0,0 +1,21 @@ +// Learn more https://docs.expo.io/guides/customizing-metro +const { getDefaultConfig } = require('expo/metro-config'); + +/** @type {import('expo/metro-config').MetroConfig} */ +const config = getDefaultConfig(__dirname); + +const { transformer, resolver } = config; + +config.transformer = { + ...transformer, + babelTransformerPath: require.resolve('react-native-svg-transformer/expo'), +}; +config.resolver = { + ...resolver, + assetExts: resolver.assetExts.filter((ext) => ext !== 'svg'), + sourceExts: [...resolver.sourceExts, 'svg'], +}; + +config.resolver.assetExts.push('pte'); + +module.exports = config; diff --git a/apps/text-embeddings/package.json b/apps/text-embeddings/package.json index 137e291601..03f2d02e32 100644 --- a/apps/text-embeddings/package.json +++ b/apps/text-embeddings/package.json @@ -1,7 +1,7 @@ { "name": "text-embeddings", "version": "1.0.0", - "main": "index.ts", + "main": "expo-router/entry", "scripts": { "start": "expo start", "android": "expo run:android", @@ -11,14 +11,25 @@ "lint": "eslint . --ext .ts,.tsx --fix" }, "peerDependencies": { + "@react-navigation/native": "*", "react-native": "*" }, "dependencies": { + "@react-navigation/drawer": "^7.4.2", "expo": "^53.0.0", + "expo-constants": "~17.1.6", + "expo-linking": "~7.1.5", + "expo-router": "~5.1.0", "expo-status-bar": "~2.2.3", "react": "19.0.0", "react-native": "0.79.2", - "react-native-executorch": "workspace:*" + "react-native-executorch": "workspace:*", + "react-native-gesture-handler": "~2.24.0", + "react-native-image-picker": "^7.2.2", + "react-native-reanimated": "~3.17.4", + "react-native-safe-area-context": "5.4.0", + "react-native-screens": "~4.11.1", + "react-native-svg": "15.11.2" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/docs/docs/computer-vision/useImageEmbeddings.md b/docs/docs/computer-vision/useImageEmbeddings.md new file mode 100644 index 0000000000..90e97c0b85 --- /dev/null +++ b/docs/docs/computer-vision/useImageEmbeddings.md @@ -0,0 +1,121 @@ +--- +title: useImageEmbeddings +keywords: + [ + image embedding, + image embeddings, + embeddings, + react native, + executorch, + ai, + machine learning, + on-device, + mobile ai, + clip, + ] +description: "Learn how to use image embeddings models in your React Native applications with React Native ExecuTorch's useImageEmbeddings hook." +--- + +Image Embedding is the process of converting an image into a numerical representation. This representation can be used for tasks, such as classification, clustering and (using contrastive learning like e.g. CLIP model) image search. + +:::caution +It is recommended to use models provided by us, which are available at our [Hugging Face repository](https://huggingface.co/software-mansion/react-native-executorch-clip-vit-base-patch32-image-encoder). You can also use [constants](https://github.com/software-mansion/react-native-executorch/tree/main/src/constants/modelUrls.ts) shipped with our library. +::: + +## Reference + +```typescript +import { + useImageEmbeddings, + CLIP_VIT_BASE_PATCH_32_IMAGE_ENCODER_MODEL, +} from 'react-native-executorch'; + +const model = useImageEmbeddings({ + modelSource: CLIP_VIT_BASE_PATCH_32_IMAGE_ENCODER_MODEL, +}); + +try { + const imageEmbedding = await model.forward('https://url-to-image.jpg'); +} catch (error) { + console.error(error); +} +``` + +### Arguments + +**`modelSource`** +A string that specifies the location of the model binary. For more information, take a look at [loading models](../fundamentals/loading-models.md) page. + +**`preventLoad?`** - Boolean that can prevent automatic model loading (and downloading the data if you load it for the first time) after running the hook. + +### Returns + +| Field | Type | Description | +| ------------------ | ------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `forward` | `(input: imageSource) => Promise` | Executes the model's forward pass, where `input` is a URI/URL to image that will be embedded. | +| `error` | string | null | Contains the error message if the model failed to load. | +| `isGenerating` | `boolean` | Indicates whether the model is currently processing an inference. | +| `isReady` | `boolean` | Indicates whether the model has successfully loaded and is ready for inference. | +| `downloadProgress` | `number` | Represents the download progress as a value between 0 and 1. | + +## Running the model + +To run the model, you can use the `forward` method. It accepts one argument which is a URI/URL to an image you want to encode. The function returns a promise, which can resolve either to an error or an array of numbers representing the embedding. + +:::info +The returned embedding vector is normalized, meaning that its length is equal to 1. This allows for easier comparison of vectors using cosine similarity, just calculate the dot product of two vectors to get the cosine similarity score. +::: + +## Example + +```typescript +const dotProduct = (a: number[], b: number[]) => + a.reduce((sum, val, i) => sum + val * b[i], 0); + +try { + // we assume you've provided catImage and dogImage + const catImageEmbedding = await model.forward(catImage); + const dogImageEmbedding = await model.forward(dogImage); + + // The embeddings are normalized, so we can use dot product to calculate cosine similarity + const similarity = dotProduct(catImageEmbedding, dogImageEmbedding); + + console.log(`Cosine similarity: ${similarity}`); +} catch (error) { + console.error(error); +} +``` + +## Supported models + +| Model | Language | Image size | Embedding Dimensions | Description | +| ------------------------------------------------------------------------------------------ | :------: | :--------: | :------------------: | -------------------------------------------------------------- | +| [clip-vit-base-patch32-image-encoder](https://huggingface.co/openai/clip-vit-base-patch32) | English | 224 x 224 | 512 | Trained using contrastive learning for image search use cases. | + +**`Image size`** - the size of an image that the model takes as an input. Resize will happen automatically. + +**`Embedding Dimensions`** - the size of the output embedding vector. This is the number of dimensions in the vector representation of the input image. + +## Benchmarks + +### Model size + +| Model | XNNPACK [MB] | +| ---------------------- | :----------: | +| CLIP_VIT_BASE_PATCH_32 | 352 | + +### Memory usage + +| Model | Android (XNNPACK) [MB] | iOS (XNNPACK) [MB] | +| ---------------------- | :--------------------: | :----------------: | +| CLIP_VIT_BASE_PATCH_32 | 324 | 347 | + +### Inference time + +:::warning warning +Times presented in the tables are measured as consecutive runs of the model. Initial run times may be up to 2x longer due to model loading and initialization. Performance also heavily depends on image size, because resize is expansive operation, especially on low-end devices. +::: + +| Model | iPhone 16 Pro (XNNPACK) [ms] | iPhone 14 Pro Max (XNNPACK) [ms] | iPhone SE 3 (XNNPACK) [ms] | Samsung Galaxy S24 (XNNPACK) [ms] | +| ---------------------- | :--------------------------: | :------------------------------: | :------------------------: | :-------------------------------: | +| CLIP_VIT_BASE_PATCH_32 | 104 | 120 | 280 | 265 | diff --git a/docs/docs/natural-language-processing/useTextEmbeddings.md b/docs/docs/natural-language-processing/useTextEmbeddings.md index 03945110a6..a9e2ef329b 100644 --- a/docs/docs/natural-language-processing/useTextEmbeddings.md +++ b/docs/docs/natural-language-processing/useTextEmbeddings.md @@ -133,6 +133,7 @@ function App() { | ALL_MPNET_BASE_V2 | 438 | | MULTI_QA_MINILM_L6_COS_V1 | 91 | | MULTI_QA_MPNET_BASE_DOT_V1 | 438 | +| CLIP_TEXT_ENCODER | 254 | ### Memory usage @@ -142,6 +143,7 @@ function App() { | ALL_MPNET_BASE_V2 | 520 | 470 | | MULTI_QA_MINILM_L6_COS_V1 | 160 | 225 | | MULTI_QA_MPNET_BASE_DOT_V1 | 540 | 500 | +| CLIP_TEXT_ENCODER | 275 | 250 | ### Inference time @@ -155,3 +157,4 @@ Times presented in the tables are measured as consecutive runs of the model. Ini | ALL_MPNET_BASE_V2 | 352 | 423 | 478 | 521 | 527 | | MULTI_QA_MINILM_L6_COS_V1 | 135 | 166 | 180 | 158 | 165 | | MULTI_QA_MPNET_BASE_DOT_V1 | 503 | 598 | 680 | 694 | 743 | +| CLIP_TEXT_ENCODER | 35 | 48 | 49 | 40 | - | diff --git a/docs/docs/typescript-api/ImageEmbeddingsModule.md b/docs/docs/typescript-api/ImageEmbeddingsModule.md new file mode 100644 index 0000000000..1fa46f434d --- /dev/null +++ b/docs/docs/typescript-api/ImageEmbeddingsModule.md @@ -0,0 +1,51 @@ +--- +title: ImageEmbeddingsModule +--- + +TypeScript API implementation of the [useImageEmbeddings](../computer-vision/useImageEmbeddings.md) hook. + +## Reference + +```typescript +import { + ImageEmbeddingsModule, + CLIP_VIT_BASE_PATCH_32_IMAGE_ENCODER, +} from 'react-native-executorch'; + +// Loading the model +await ImageEmbeddingsModule.load(CLIP_VIT_BASE_PATCH_32_IMAGE_ENCODER); + +// Running the model +const embedding = await ImageEmbeddingsModule.forward( + 'https://url-to-image.jpg' +); +``` + +### Methods + +| Method | Type | Description | +| -------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| `load` | `(modelSource: ResourceSource): Promise` | Loads the model, where `modelSource` is a string that specifies the location of the model binary. | +| `forward` | `(input: string): Promise` | Executes the model's forward pass, where `input` is a URI/URL to image that will be embedded. | +| `onDownloadProgress` | `(callback: (downloadProgress: number) => void): any` | Subscribe to the download progress event. | + +
+Type definitions + +```typescript +type ResourceSource = string | number | object; +``` + +
+ +## Loading the model + +To load the model, use the `load` method. It accepts the `modelSource` which is a string that specifies the location of the model binary. For more information, take a look at [loading models](../fundamentals/loading-models.md) page. This method returns a promise, which can resolve to an error or void. + +## Running the model + +It accepts one argument, which is a URI/URL to an image you want to encode. The function returns a promise, which can resolve either to an error or an array of numbers representing the embedding. + +:::info +The returned embedding vector is normalized, meaning that its length is equal to 1. This allows for easier comparison of vectors using cosine similarity, just calculate the dot product of two vectors to get the cosine similarity score. +::: diff --git a/docs/sidebars.js b/docs/sidebars.js index 36fe1e20e7..e7d393662e 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -57,6 +57,7 @@ const sidebars = { 'computer-vision/useClassification', 'computer-vision/useObjectDetection', 'computer-vision/useStyleTransfer', + 'computer-vision/useImageEmbeddings', ], }, { @@ -100,6 +101,7 @@ const sidebars = { 'typescript-api/ClassificationModule', 'typescript-api/ObjectDetectionModule', 'typescript-api/StyleTransferModule', + 'typescript-api/ImageEmbeddingsModule', ], }, { diff --git a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp index 3122867bde..5d1fe3dc85 100644 --- a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp +++ b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,11 @@ void RnExecutorchInstaller::injectJSIBindings( *jsiRuntime, "loadTokenizerModule", RnExecutorchInstaller::loadModel( jsiRuntime, jsCallInvoker, "loadTokenizerModule")); + + jsiRuntime->global().setProperty( + *jsiRuntime, "loadImageEmbeddings", + RnExecutorchInstaller::loadModel( + jsiRuntime, jsCallInvoker, "loadImageEmbeddings")); } } // namespace rnexecutorch \ No newline at end of file diff --git a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h index 53e0401262..4f36d6f7e3 100644 --- a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h +++ b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h @@ -30,6 +30,8 @@ REGISTER_CONSTRUCTOR(BaseModel, std::string, std::shared_ptr); REGISTER_CONSTRUCTOR(TokenizerModule, std::string, std::shared_ptr); +REGISTER_CONSTRUCTOR(ImageEmbeddings, std::string, + std::shared_ptr); using namespace facebook; diff --git a/packages/react-native-executorch/common/rnexecutorch/TokenizerModule.cpp b/packages/react-native-executorch/common/rnexecutorch/TokenizerModule.cpp index 42664b4384..5981040be3 100644 --- a/packages/react-native-executorch/common/rnexecutorch/TokenizerModule.cpp +++ b/packages/react-native-executorch/common/rnexecutorch/TokenizerModule.cpp @@ -1,7 +1,6 @@ #include "TokenizerModule.h" #include #include -#include #include namespace rnexecutorch { diff --git a/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.cpp b/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.cpp index 618683f007..01006077a8 100644 --- a/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.cpp +++ b/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.cpp @@ -1,6 +1,7 @@ #include "Numerical.h" #include +#include #include namespace rnexecutorch::numerical { @@ -16,4 +17,17 @@ void softmax(std::vector &v) { x /= sum; } } + +void normalize(std::span span) { + auto sum = 0.0f; + for (const auto &val : span) { + sum += val * val; + } + + // Preventing divison by 0 + float norm = std::max(std::sqrt(sum), 1e-9f); + for (auto &val : span) { + val /= norm; + } +} } // namespace rnexecutorch::numerical \ No newline at end of file diff --git a/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.h b/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.h index 66d96b51ee..9189cfb221 100644 --- a/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.h +++ b/packages/react-native-executorch/common/rnexecutorch/data_processing/Numerical.h @@ -1,7 +1,9 @@ #pragma once +#include #include namespace rnexecutorch::numerical { void softmax(std::vector &v); +void normalize(std::span span); } // namespace rnexecutorch::numerical \ No newline at end of file diff --git a/packages/react-native-executorch/common/rnexecutorch/host_objects/JsiConversions.h b/packages/react-native-executorch/common/rnexecutorch/host_objects/JsiConversions.h index d04eed18f1..baceeb72ac 100644 --- a/packages/react-native-executorch/common/rnexecutorch/host_objects/JsiConversions.h +++ b/packages/react-native-executorch/common/rnexecutorch/host_objects/JsiConversions.h @@ -216,6 +216,12 @@ inline jsi::Value getJsiValue(const std::vector &vec, return jsi::Value(runtime, array); } +inline jsi::Value getJsiValue(const std::shared_ptr &buf, + jsi::Runtime &runtime) { + jsi::ArrayBuffer arrayBuffer(runtime, buf); + return jsi::Value(runtime, arrayBuffer); +} + inline jsi::Value getJsiValue(const std::string &str, jsi::Runtime &runtime) { return jsi::String::createFromAscii(runtime, str); } diff --git a/packages/react-native-executorch/common/rnexecutorch/models/image_embeddings/ImageEmbeddings.cpp b/packages/react-native-executorch/common/rnexecutorch/models/image_embeddings/ImageEmbeddings.cpp new file mode 100644 index 0000000000..45c5474b5a --- /dev/null +++ b/packages/react-native-executorch/common/rnexecutorch/models/image_embeddings/ImageEmbeddings.cpp @@ -0,0 +1,60 @@ +#include "ImageEmbeddings.h" + +#include +#include +#include +namespace rnexecutorch { + +ImageEmbeddings::ImageEmbeddings( + const std::string &modelSource, + std::shared_ptr callInvoker) + : BaseModel(modelSource, callInvoker) { + auto inputTensors = getAllInputShapes(); + if (inputTensors.size() == 0) { + throw std::runtime_error("Model seems to not take any input tensors."); + } + std::vector modelInputShape = inputTensors[0]; + if (modelInputShape.size() < 2) { + char errorMessage[100]; + std::snprintf(errorMessage, sizeof(errorMessage), + "Unexpected model input size, expected at least 2 dimentions " + "but got: %zu.", + modelInputShape.size()); + throw std::runtime_error(errorMessage); + } + modelImageSize = cv::Size(modelInputShape[modelInputShape.size() - 1], + modelInputShape[modelInputShape.size() - 2]); +} + +std::shared_ptr +ImageEmbeddings::generate(std::string imageSource) { + auto [inputTensor, originalSize] = + imageprocessing::readImageToTensor(imageSource, getAllInputShapes()[0]); + + auto result = BaseModel::forward(inputTensor); + if (!result.ok()) { + throw std::runtime_error("Forward pass failed: Error " + + std::to_string(static_cast(result.error()))); + } + + auto &outputs = result.get(); + + if (outputs.size() > 1) { + throw std::runtime_error("It returned multiple outputs!"); + } + + auto &outputTensor = outputs.at(0).toTensor(); + std::span outputTensorSpan( + static_cast(outputTensor.mutable_data_ptr()), + outputTensor.numel()); + + numerical::normalize(outputTensorSpan); + + size_t bufferSize = outputTensorSpan.size_bytes(); + auto buffer = std::make_shared(bufferSize); + + std::memcpy(buffer->data(), outputTensorSpan.data(), bufferSize); + + return buffer; +} +} // namespace rnexecutorch diff --git a/packages/react-native-executorch/common/rnexecutorch/models/image_embeddings/ImageEmbeddings.h b/packages/react-native-executorch/common/rnexecutorch/models/image_embeddings/ImageEmbeddings.h new file mode 100644 index 0000000000..bbbe30413b --- /dev/null +++ b/packages/react-native-executorch/common/rnexecutorch/models/image_embeddings/ImageEmbeddings.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +#include + +namespace rnexecutorch { +using executorch::extension::TensorPtr; +using executorch::runtime::EValue; + +class ImageEmbeddings : public BaseModel { +public: + ImageEmbeddings(const std::string &modelSource, + std::shared_ptr callInvoker); + std::shared_ptr generate(std::string imageSource); + +private: + cv::Size modelImageSize{0, 0}; +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/packages/react-native-executorch/src/constants/modelUrls.ts b/packages/react-native-executorch/src/constants/modelUrls.ts index 757ce66f19..b7e83f4798 100644 --- a/packages/react-native-executorch/src/constants/modelUrls.ts +++ b/packages/react-native-executorch/src/constants/modelUrls.ts @@ -162,6 +162,10 @@ export const DETECTOR_CRAFT_320 = export const DEEPLAB_V3_RESNET50 = 'https://huggingface.co/software-mansion/react-native-executorch-deeplab-v3/resolve/v0.4.0/xnnpack/deeplabV3_xnnpack_fp32.pte'; +// Image Embeddings +export const CLIP_VIT_BASE_PATCH_32_IMAGE_ENCODER_MODEL = + 'https://huggingface.co/software-mansion/react-native-executorch-clip-vit-base-patch32-image-encoder/resolve/v0.5.0/clip-vit-base-patch32-image-encoder-float32.pte'; + // Text Embeddings export const ALL_MINILM_L6_V2 = 'https://huggingface.co/software-mansion/react-native-executorch-all-MiniLM-L6-v2/resolve/v0.4.0/all-MiniLM-L6-v2_xnnpack.pte'; @@ -183,6 +187,17 @@ export const MULTI_QA_MPNET_BASE_DOT_V1 = export const MULTI_QA_MPNET_BASE_DOT_V1_TOKENIZER = 'https://huggingface.co/software-mansion/react-native-executorch-multi-qa-mpnet-base-dot-v1/resolve/v0.4.0/tokenizer.json'; +export const CLIP_VIT_BASE_PATCH_32_TEXT_ENCODER_MODEL = + 'https://huggingface.co/software-mansion/react-native-executorch-clip-vit-base-patch32-text-encoder/resolve/v0.5.0/clip-vit-base-patch32-text-encoder-float32.pte'; +export const CLIP_VIT_BASE_PATCH_32_TEXT_ENCODER_TOKENIZER = + 'https://huggingface.co/software-mansion/react-native-executorch-clip-vit-base-patch32-text-encoder/resolve/v0.5.0/tokenizer.json'; + +export const CLIP_VIT_BASE_PATCH_32_TEXT_ENCODER = { + modelSource: CLIP_VIT_BASE_PATCH_32_TEXT_ENCODER_MODEL, + tokenizerSource: CLIP_VIT_BASE_PATCH_32_TEXT_ENCODER_TOKENIZER, + meanPooling: false, +}; + // Backward compatibility export const LLAMA3_2_3B_URL = LLAMA3_2_3B; export const LLAMA3_2_3B_QLORA_URL = LLAMA3_2_3B_QLORA; diff --git a/packages/react-native-executorch/src/hooks/computer_vision/useImageEmbeddings.ts b/packages/react-native-executorch/src/hooks/computer_vision/useImageEmbeddings.ts new file mode 100644 index 0000000000..e81de1855c --- /dev/null +++ b/packages/react-native-executorch/src/hooks/computer_vision/useImageEmbeddings.ts @@ -0,0 +1,16 @@ +import { ImageEmbeddingsModule } from '../../modules/computer_vision/ImageEmbeddingsModule'; +import { ResourceSource } from '../../types/common'; +import { useNonStaticModule } from '../useNonStaticModule'; + +export const useImageEmbeddings = ({ + modelSource, + preventLoad = false, +}: { + modelSource: ResourceSource; + preventLoad?: boolean; +}) => + useNonStaticModule({ + module: ImageEmbeddingsModule, + loadArgs: [modelSource], + preventLoad, + }); diff --git a/packages/react-native-executorch/src/hooks/useNonStaticModule.ts b/packages/react-native-executorch/src/hooks/useNonStaticModule.ts index e28390409e..04a1c8e2d9 100644 --- a/packages/react-native-executorch/src/hooks/useNonStaticModule.ts +++ b/packages/react-native-executorch/src/hooks/useNonStaticModule.ts @@ -14,7 +14,7 @@ interface ModuleConstructor { export const useNonStaticModule = < M extends Module, LoadArgs extends Parameters, - ForwardArgs extends any[], + ForwardArgs extends Parameters, ForwardReturn extends Awaited>, >({ module, diff --git a/packages/react-native-executorch/src/index.tsx b/packages/react-native-executorch/src/index.tsx index 0af19b0c3e..60bd3ec397 100644 --- a/packages/react-native-executorch/src/index.tsx +++ b/packages/react-native-executorch/src/index.tsx @@ -10,6 +10,7 @@ declare global { var loadObjectDetection: (source: string) => any; var loadExecutorchModule: (source: string) => any; var loadTokenizerModule: (source: string) => any; + var loadImageEmbeddings: (source: string) => any; } // eslint-disable no-var if ( @@ -35,6 +36,7 @@ export * from './hooks/computer_vision/useStyleTransfer'; export * from './hooks/computer_vision/useImageSegmentation'; export * from './hooks/computer_vision/useOCR'; export * from './hooks/computer_vision/useVerticalOCR'; +export * from './hooks/computer_vision/useImageEmbeddings'; export * from './hooks/natural_language_processing/useLLM'; export * from './hooks/natural_language_processing/useSpeechToText'; @@ -51,6 +53,7 @@ export * from './modules/computer_vision/ImageSegmentationModule'; export * from './modules/computer_vision/OCRModule'; export * from './modules/computer_vision/VerticalOCRModule'; export * from './modules/general/ExecutorchModule'; +export * from './modules/computer_vision/ImageEmbeddingsModule'; export * from './modules/natural_language_processing/LLMModule'; export * from './modules/natural_language_processing/SpeechToTextModule'; diff --git a/packages/react-native-executorch/src/modules/computer_vision/ImageEmbeddingsModule.ts b/packages/react-native-executorch/src/modules/computer_vision/ImageEmbeddingsModule.ts new file mode 100644 index 0000000000..375c708b43 --- /dev/null +++ b/packages/react-native-executorch/src/modules/computer_vision/ImageEmbeddingsModule.ts @@ -0,0 +1,23 @@ +import { ResourceFetcher } from '../../utils/ResourceFetcher'; +import { ResourceSource } from '../../types/common'; +import { ETError, getError } from '../../Error'; +import { BaseNonStaticModule } from '../BaseNonStaticModule'; + +export class ImageEmbeddingsModule extends BaseNonStaticModule { + async load( + modelSource: ResourceSource, + onDownloadProgressCallback: (_: number) => void = () => {} + ): Promise { + const paths = await ResourceFetcher.fetchMultipleResources( + onDownloadProgressCallback, + modelSource + ); + this.nativeModule = global.loadImageEmbeddings(paths[0] || ''); + } + + async forward(imageSource: string): Promise { + if (this.nativeModule == null) + throw new Error(getError(ETError.ModuleNotLoaded)); + return new Float32Array(await this.nativeModule.generate(imageSource)); + } +} diff --git a/packages/react-native-executorch/src/types/common.ts b/packages/react-native-executorch/src/types/common.ts index 3b375c338f..b4567b2b0e 100644 --- a/packages/react-native-executorch/src/types/common.ts +++ b/packages/react-native-executorch/src/types/common.ts @@ -1,12 +1,3 @@ -export const getTypeIdentifier = (input: ETInput): number => { - if (input instanceof Int8Array) return 1; - if (input instanceof Int32Array) return 3; - if (input instanceof BigInt64Array) return 4; - if (input instanceof Float32Array) return 6; - if (input instanceof Float64Array) return 7; - return -1; -}; - export type ResourceSource = string | number | object; export type ETInput = diff --git a/yarn.lock b/yarn.lock index 8137a06976..714f094e46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3755,6 +3755,26 @@ __metadata: languageName: node linkType: hard +"@react-navigation/drawer@npm:^7.4.2": + version: 7.5.2 + resolution: "@react-navigation/drawer@npm:7.5.2" + dependencies: + "@react-navigation/elements": "npm:^2.5.2" + color: "npm:^4.2.3" + react-native-drawer-layout: "npm:^4.1.11" + use-latest-callback: "npm:^0.2.4" + peerDependencies: + "@react-navigation/native": ^7.1.14 + react: ">= 18.2.0" + react-native: "*" + react-native-gesture-handler: ">= 2.0.0" + react-native-reanimated: ">= 2.0.0" + react-native-safe-area-context: ">= 4.0.0" + react-native-screens: ">= 4.0.0" + checksum: 10/17907a0d0e5a260946902e81a9dac327366387c02f4a3f2c0938a9e6106874c552d57af4cf1441688e2e47fad891a72cff01635a58e7af316e72c232f82fb3d1 + languageName: node + linkType: hard + "@react-navigation/elements@npm:^2.4.3": version: 2.4.3 resolution: "@react-navigation/elements@npm:2.4.3" @@ -3773,6 +3793,26 @@ __metadata: languageName: node linkType: hard +"@react-navigation/elements@npm:^2.5.2": + version: 2.5.2 + resolution: "@react-navigation/elements@npm:2.5.2" + dependencies: + color: "npm:^4.2.3" + use-latest-callback: "npm:^0.2.4" + use-sync-external-store: "npm:^1.5.0" + peerDependencies: + "@react-native-masked-view/masked-view": ">= 0.2.0" + "@react-navigation/native": ^7.1.14 + react: ">= 18.2.0" + react-native: "*" + react-native-safe-area-context: ">= 4.0.0" + peerDependenciesMeta: + "@react-native-masked-view/masked-view": + optional: true + checksum: 10/f6c472f82487661aee6f41e82e453cb80fea85e3956d94e58aa45b7c3f5ae04e4862df400439d0a58e6c54f8e091d7e08c547a153165d881fa8c74fd3b63d6a3 + languageName: node + linkType: hard + "@react-navigation/native-stack@npm:^7.3.10": version: 7.3.14 resolution: "@react-navigation/native-stack@npm:7.3.14" @@ -7349,6 +7389,43 @@ __metadata: languageName: node linkType: hard +"expo-router@npm:~5.1.0": + version: 5.1.0 + resolution: "expo-router@npm:5.1.0" + dependencies: + "@expo/metro-runtime": "npm:5.0.4" + "@expo/server": "npm:^0.6.2" + "@radix-ui/react-slot": "npm:1.2.0" + "@react-navigation/bottom-tabs": "npm:^7.3.10" + "@react-navigation/native": "npm:^7.1.6" + "@react-navigation/native-stack": "npm:^7.3.10" + client-only: "npm:^0.0.1" + invariant: "npm:^2.2.4" + react-fast-compare: "npm:^3.2.2" + react-native-is-edge-to-edge: "npm:^1.1.6" + schema-utils: "npm:^4.0.1" + semver: "npm:~7.6.3" + server-only: "npm:^0.0.1" + shallowequal: "npm:^1.1.0" + peerDependencies: + "@react-navigation/drawer": ^7.3.9 + expo: "*" + expo-constants: "*" + expo-linking: "*" + react-native-reanimated: "*" + react-native-safe-area-context: "*" + react-native-screens: "*" + peerDependenciesMeta: + "@react-navigation/drawer": + optional: true + "@testing-library/jest-native": + optional: true + react-native-reanimated: + optional: true + checksum: 10/32341130130e9ab14b1501e2a2631a799a07156ff20e5b7338d1a02fa514c77641fbb72605eafbdbbe46ac5db2282de1d42c56e7a43df4004071ccb0ce2c6ffa + languageName: node + linkType: hard + "expo-status-bar@npm:~2.2.3": version: 2.2.3 resolution: "expo-status-bar@npm:2.2.3" @@ -12427,6 +12504,20 @@ __metadata: languageName: node linkType: hard +"react-native-drawer-layout@npm:^4.1.11": + version: 4.1.11 + resolution: "react-native-drawer-layout@npm:4.1.11" + dependencies: + use-latest-callback: "npm:^0.2.4" + peerDependencies: + react: ">= 18.2.0" + react-native: "*" + react-native-gesture-handler: ">= 2.0.0" + react-native-reanimated: ">= 2.0.0" + checksum: 10/0ddd58abeeb86a4fbc1731d00acda4457c7750076717e9ce0b194ec03a985922ba12a86074040a214377a4e1bb59f45693bf3af2b6714fb2d4740d3528e8d944 + languageName: node + linkType: hard + "react-native-edge-to-edge@npm:1.6.0": version: 1.6.0 resolution: "react-native-edge-to-edge@npm:1.6.0" @@ -14010,13 +14101,24 @@ __metadata: resolution: "text-embeddings@workspace:apps/text-embeddings" dependencies: "@babel/core": "npm:^7.25.2" + "@react-navigation/drawer": "npm:^7.4.2" "@types/react": "npm:~19.0.10" expo: "npm:^53.0.0" + expo-constants: "npm:~17.1.6" + expo-linking: "npm:~7.1.5" + expo-router: "npm:~5.1.0" expo-status-bar: "npm:~2.2.3" react: "npm:19.0.0" react-native: "npm:0.79.2" react-native-executorch: "workspace:*" + react-native-gesture-handler: "npm:~2.24.0" + react-native-image-picker: "npm:^7.2.2" + react-native-reanimated: "npm:~3.17.4" + react-native-safe-area-context: "npm:5.4.0" + react-native-screens: "npm:~4.11.1" + react-native-svg: "npm:15.11.2" peerDependencies: + "@react-navigation/native": "*" react-native: "*" languageName: unknown linkType: soft @@ -14433,6 +14535,15 @@ __metadata: languageName: node linkType: hard +"use-latest-callback@npm:^0.2.4": + version: 0.2.4 + resolution: "use-latest-callback@npm:0.2.4" + peerDependencies: + react: ">=16.8" + checksum: 10/60c3a6b1b6567e1794f9e48cd86b8cde8a149485cc2fed60570f69ec3b157f6812e0ff0a877f0b971592fb9254b1363cc21c120fd1fc993b1dad1406c69211df + languageName: node + linkType: hard + "use-sync-external-store@npm:^1.5.0": version: 1.5.0 resolution: "use-sync-external-store@npm:1.5.0"