Passio Nutrition-AI
  • Nutrition-AI SDK Overview
  • Guides
    • Nutrition AI SDK
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
        • User created foods and reports
    • iOS SDK Docs
      • Before getting started
      • Getting the ml models to the device
      • Run the demos first
      • Adding Passio SDK into your project
      • Initialize and configure the SDK
      • Start/Stop food detection
      • Food Recognition Delegate
      • Migration from SDK 1.4.X to 2.x
      • SDK API
      • Quick Start Guide
        • Installation
        • Configure the SDK (UIKit)
        • Recognise food using image
        • Food Details
    • Android SDK Docs
      • Getting started
        • Include the library
        • Camera
        • SDK Initialization and Configuration
        • Food detection session
        • Visual, Barcode and Packaged Food detection
        • Nutritional Database
        • Sandbox app
      • Troubleshooting on Android
      • Migration from SDK version 1.4.x to 2.x
      • Quick Start Guide
        • Importing the Android SDK to a project
        • Configure SDK and handle the result
        • RecognizeImageRemote
        • Food Details
    • React Native SDK Docs
      • Getting Started
        • Installation
        • SDK Initialization and Configuration
      • API Reference
        • configure & requestCameraAuthorization
        • recognizeImageRemote
        • searchForFood & searchForFoodSemantic
        • startFoodDetection
          • FoodDetectionEvent
        • fetchFoodItemForProductCode
        • fetchFoodItemForRefCode
        • fetchFoodItemForDataInfo
        • startNutritionFactsDetection
        • fetchFoodItemForPassioID
        • recognizeSpeechRemote
        • Fetch Nutrients
        • onDowloadingPassioModelCallBacks
        • detectFoodFromImageURI
        • addToPersonalization
        • updateLanguage
        • fetchHiddenIngredients
        • fetchVisualAlternatives
        • fetchPossibleIngredients
      • Properties
        • PassioFoodItem
        • PassioFoodDataInfo
        • PassioFoodAmount
        • PassioIngredient
        • PassioNutrients
        • UnitMass
        • ServingUnit
        • ServingSize
        • PassioSearchResult
        • NutritionFacts
        • PassioNutritionPreview
        • PassioSpeechRecognitionModel
        • PassioLogAction
        • PassioAdvisorFoodInfo
        • FoodCandidates
        • FoodDetectionEvent
        • NutritionDetectionEvent
        • DetectedCandidate
        • BarcodeCandidate
        • PackagedFoodCode
        • AmountEstimate
        • ImagesInfo
        • PassioStatus
        • FoodDetectionEvent
        • NutritionFacts
        • PassioMealPlan
        • PassioMealPlanItem
      • Nutriton Advisor
        • initConversation
        • sendMessage
        • sendImage
        • Guide
          • useNutritionAdvisor
        • Properties
          • PassioAdvisorResponse
          • PassioAdvisorMessageResultStatus
          • PassioAdvisorResultStatus
      • Quick Start Guide
        • Installation
        • Configure the SDK
        • RecognizeImageRemote
        • Food Detail
      • Guide
        • Integrate SDK Setup
        • Integrate Quick Scan
        • Integrate Food Search
        • Integrate Food Editor with Recipe
        • Integrate MealPlan
        • Integrate Suggestions
        • Integrate recognizeImageRemote
      • Components
        • DetectionCameraView
        • PassioIconView
      • Changelog
      • More
        • Display Macro Chart
          • MockFood
          • Utils PassioNutrient
        • Display Micro Progress
        • Getting nutrition value for a FoodItem
        • Getting nutrition value for a Recipe
        • Recalculate the nutrition value based on serving size options.
      • Migrations
        • Migrating from SDK 2.X to version 3.X
        • Structure Migrations From SDK 3.X to SDK 2.X
        • [Deprecated] Migrating from SDK 1.X to version 2.X
        • [Deprecated] Getting Started (v1)
          • Installation
          • SDK Initialization and Configuration
          • Start food detection
          • FoodDetectionEvent
          • Nutritional Database
      • Troubleshooting on RN
      • V2
        • Getting Started
          • Installation
          • SDK Initialization and Configuration
          • Start food detection
          • FoodDetectionEvent
        • RN SDK API
          • Properties
            • PersonalizedAlternative
            • FoodSearchResult
            • PassioNutrient
            • FoodDetectionEvent
            • DownloadModelCallBack
            • UPCProduct
            • ServingUnit
            • PassioStatus
            • PassioIDAttributes
            • PassioIDEntityType
            • PassioFoodItem
            • PassioRecipe
            • ServingSize
            • Measurement
            • UnitMass
            • NutritionFacts
        • Food Image
        • Search Food Item
        • Quick Scan
        • Multi Scan
        • MealPlan
        • Recipe
      • How do I Integrate a Passio SDK in EXPO?
    • Flutter SDK Docs
      • Getting Started
    • Before You Continue
    • Setup For Android
    • Initialize and configure the SDK
  • Fundamentals
    • Nutrition-AI Developer FAQ
      • Nutrition Data
      • Supported Phones
      • Security
      • Testing Volume Estimation
      • Testing Nutrition-AI SDK
      • Nutrition-AI Test Methodology
    • Nutrition API - Mobile SDK interoperability
      • JSON Response parsing
  • Versions
    • 3.2.4
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
        • User created foods and reports
    • 3.2.2
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
        • User created foods and reports
    • 3.2.0
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
    • 3.1.4
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
Powered by GitBook
On this page
  • How can I implement the startFoodDetection API and retrieve food items through quick scan?
  • Example
  • useQuickScan
  • QuickScanningScreen
  • QuickFoodResult
  • AlternativeFood
  • Utility Methods
  • Result
Export as PDF
  1. Guides
  2. React Native SDK Docs
  3. V2

Quick Scan

You can utilize the `startFoodDetection` API to scan food items through the device Camera.

How can I implement the startFoodDetection API and retrieve food items through quick scan?

/**
     * Begin food detection using the device's camera.
     * @param options - An object to determine which types of scanning should be performed.
     * @param callback - A callback to repeatedly receive food detection events as they occur.
     * @returns A `Subscription` that should be retained by the caller while food detection is running. Call `remove` on the subscription to terminate food detection.
     */
   
   // Configuration for food detection
   
  useEffect(() => {
    const config: FoodDetectionConfig = {
      detectBarcodes: true,
      detectPackagedFood: true,
      detectNutritionFacts: true,
    };

    // Start food detection and subscribe to events
    const subscription = PassioSDK.startFoodDetection(
      config,
      handleFoodDetection
    );

    // Cleanup function to unsubscribe when the component unmounts
    return () => subscription.remove();
  }, []); // Empty dependency array to run the effect only once during component mount

Example

In this , we establish the useQuickScan hook, which furnishes methods and data such as food, and use of DetectionCameraVieimport React from 'react';

useQuickScan

import { useEffect, useRef, useState, useCallback } from 'react';
import {
  PassioSDK,
  type PassioIDAttributes,
  type FoodDetectionConfig,
  type NutritionFacts,
  type FoodDetectionEvent,
} from '@passiolife/nutritionai-react-native-sdk-v2';
import { getAlternateFoodItems } from '../utils';

/**
 * Custom hook for handling quick food scanning using PassioSDK.
 * It provides functions and state variables related to food detection and alternative food items.
 */
export const useQuickScan = () => {
  // State variables
  const [passioIDAttributes, setPassioIDAttributes] =
    useState<PassioIDAttributes | null>(null);
  const [alternative, setAlternativePassioIDAttributes] = useState<
    PassioIDAttributes[] | null
  >(null);
  const [loading, setLoading] = useState(true);
  const passioIDAttributesRef = useRef<PassioIDAttributes | null>(null);
  
const [nutritionFacts, setNutritionFacts] = useState<
    NutritionFacts | undefined
  >(undefined);


  // Function to clear the scanning results
  const onClearResultPress = () => {
    setLoading(true);
    passioIDAttributesRef.current = null;
    setPassioIDAttributes(null);
    setAlternativePassioIDAttributes(null);
  };

  useEffect(() => {
    // Function to handle food detection events
    const handleFoodDetection = async (detection: FoodDetectionEvent) => {
      const { candidates , nutritionFacts} = detection;
    
        if (
          nutritionFacts !== undefined &&
          nutritionFacts.servingSizeGram !== undefined
        ) {
          setNutritionFacts(detection.nutritionFacts);
          return;
        }

      if (!candidates) {
        return;
      }

      let attributes: PassioIDAttributes | null = null;

      // Determine the type of food detection and fetch attributes accordingly
      if (candidates.barcodeCandidates?.[0]) {
        const barcode = candidates.barcodeCandidates[0].barcode;
        attributes = await PassioSDK.fetchAttributesForBarcode(barcode);
      } else if (candidates.packagedFoodCode?.[0]) {
        const packagedFoodCode = candidates.packagedFoodCode[0];
        attributes =
          await PassioSDK.fetchPassioIDAttributesForPackagedFood(
            packagedFoodCode
          );
      } else if (candidates.detectedCandidates?.[0]) {
        const passioID = candidates.detectedCandidates[0].passioID;
        attributes = await PassioSDK.getAttributesForPassioID(passioID);
      }

      if (attributes === null) {
        return;
      }

      // Check if the detected food is different from the previous one
      if (attributes?.passioID !== passioIDAttributesRef.current?.passioID) {
        passioIDAttributesRef.current = attributes;
        
        // Update state variables and fetch alternative food items
        setPassioIDAttributes((prev) => {
          if (attributes?.passioID === prev?.passioID) {
            return prev;
          } else {
            async function callAlternative() {
              if (attributes) {
                const alternativeItems =
                  await getAlternateFoodItems(attributes);
                setAlternativePassioIDAttributes(alternativeItems);
              }
            }
            callAlternative();
            return attributes;
          }
        });

        setLoading(false);
      }
    };

    // Configuration for food detection
    const config: FoodDetectionConfig = {
      detectBarcodes: true,
      detectPackagedFood: true,
      detectNutritionFacts: true,
    };

    // Start food detection and subscribe to events
    const subscription = PassioSDK.startFoodDetection(
      config,
      handleFoodDetection
    );

    // Cleanup function to unsubscribe when the component unmounts
    return () => subscription.remove();
  }, []); // Empty dependency array to run the effect only once during component mount

  // Function to handle changes in alternative food items
  const onAlternativeFoodItemChange = useCallback(
    async (attribute: PassioIDAttributes) => {
      const alternativeItems = await getAlternateFoodItems(attribute);
      setAlternativePassioIDAttributes(alternativeItems);
      setPassioIDAttributes(attribute);
      passioIDAttributesRef.current = attribute;
    },
    []
  );

  // Return the hook's public API
  return {
    loading,
    passioIDAttributes,
    onAlternativeFoodItemChange,
    onClearResultPress,
    alternative,
    nutritionFacts
  };
};

QuickScanningScreen

import { ActivityIndicator, StyleSheet, View } from 'react-native';

import { DetectionCameraView } from '@passiolife/nutritionai-react-native-sdk-v2';
import { blackBackgroundStyle } from './QuickScanningScreen.Style';

import { useQuickScan } from './useQuickScan';
import { QuickFoodResult } from './views/QuickFoodResult';

export const QuickScanningScreen = () => {
  const {
    loading,
    passioIDAttributes,
    onClearResultPress,
    alternative,
    onAlternativeFoodItemChange,
  } = useQuickScan();
  const styles = quickScanStyle();

  return (
    <View style={blackBackgroundStyle}>
      <DetectionCameraView style={styles.detectionCamera} />
      {loading ? <ActivityIndicator style={styles.loadingIndicator} /> : null}
      {passioIDAttributes !== null ? (
        <QuickFoodResult
          attribute={passioIDAttributes}
          onAlternativeFoodItemChange={onAlternativeFoodItemChange}
          onClearResultPress={onClearResultPress}
          alternativeAttributes={alternative}
        />
      ) : null}
    </View>
  );
};

const quickScanStyle = () =>
  StyleSheet.create({
    detectionCamera: {
      flex: 1,
      width: '100%',
    },
    loadingIndicator: {
      backgroundColor: 'white',
      minHeight: 100,
      marginVertical: 30,
      position: 'absolute',
      bottom: 0,
      right: 16,
      left: 16,
    },
  });

QuickFoodResult

import React from 'react';
import { Image, Pressable, StyleSheet, Text, View } from 'react-native';

import {
  IconSize,
  PassioIconView,
  type PassioIDAttributes,
} from '@passiolife/nutritionai-react-native-sdk-v2';
import AlternativeFood from '../AlternativeFood';

export interface QuickFoodResultProps {
  attribute: PassioIDAttributes;
  alternativeAttributes?: PassioIDAttributes[] | null;
  onAlternativeFoodItemChange?: (item: PassioIDAttributes) => void;
  onClearResultPress?: () => void;
}

export const QuickFoodResult = ({
  attribute,
  alternativeAttributes,
  onAlternativeFoodItemChange,
  onClearResultPress,
}: QuickFoodResultProps) => {
  const styles = quickFoodResultStyle();

  return (
    <View style={styles.itemContainer}>
      <View style={styles.foodResult}>
        <PassioIconView
          style={styles.itemIcon}
          config={{
            passioID: attribute.imageName ?? attribute.passioID,
            iconSize: IconSize.PX180,
            passioIDEntityType: attribute.entityType,
          }}
        />
        <Text style={styles.itemFoodName}>{attribute.name}</Text>
      </View>
      {alternativeAttributes && (
        <AlternativeFood
          alternative={alternativeAttributes}
          onAlternativeFoodItemChange={onAlternativeFoodItemChange}
        />
      )}
      <Pressable style={styles.clearResult} onPress={onClearResultPress}>
        <Image
          resizeMode="contain"
          source={require('../../../../assets/ic_close_white.png')}
        />
      </Pressable>
    </View>
  );
};

const quickFoodResultStyle = () =>
  StyleSheet.create({
    itemContainer: {
      position: 'absolute',
      bottom: 0,
      right: 0,
      padding: 12,
      marginHorizontal: 16,
      backgroundColor: 'white',
      marginVertical: 30,
      left: 0,
    },
    foodResult: {
      flexDirection: 'row',
      alignItems: 'center',
    },
    itemFoodName: {
      flex: 1,
      textTransform: 'capitalize',
      marginHorizontal: 8,
      fontSize: 16,
    },
    itemIcon: {
      height: 60,
      width: 60,
    },
    clearResult: {
      position: 'absolute',
      top: -30,
      right: 0,
    },
  });

AlternativeFood

import React, { useCallback } from 'react';
import { FlatList, Pressable, StyleSheet, Text } from 'react-native';
import {
  IconSize,
  PassioIconView,
  type PassioIDAttributes,
} from '@passiolife/nutritionai-react-native-sdk-v2';

interface AlternativeFoodProps {
  alternative: PassioIDAttributes[];
  onAlternativeFoodItemChange?: (item: PassioIDAttributes) => void;
}

const AlternativeFood = ({
  alternative,
  onAlternativeFoodItemChange,
}: AlternativeFoodProps) => {
  const styles = alternativeFoodStyle();

  const renderItem = useCallback(
    ({ item }: { item: PassioIDAttributes }) => (
      <Pressable
        onPress={() => onAlternativeFoodItemChange?.(item)}
        style={styles.itemContainer}
      >
        <PassioIconView
          style={styles.itemIcon}
          config={{
            passioID: item.imageName ?? item.passioID,
            iconSize: IconSize.PX180,
            passioIDEntityType: item.entityType,
          }}
        />
        <Text style={styles.itemFoodName}>{item.name}</Text>
      </Pressable>
    ),
    [onAlternativeFoodItemChange, styles]
  );

  return (
    <FlatList
      horizontal
      data={alternative}
      renderItem={renderItem}
      keyExtractor={(item) => item.passioID.toString()}
    />
  );
};

const alternativeFoodStyle = () =>
  StyleSheet.create({
    itemContainer: {
      marginHorizontal: 8,
      alignItems: 'center',
      marginVertical: 16,
      flexDirection: 'row',
    },
    itemFoodName: {
      marginHorizontal: 8,
      flex: 1,
      textTransform: 'capitalize',
      fontSize: 12,
    },
    itemIcon: {
      height: 24,
      width: 24,
    },
  });

export default AlternativeFood;

Utility Methods

export async function getAlternateFoodItems(
  passioIDAttributes: PassioIDAttributes
): Promise<PassioIDAttributes[]> {
  const childrenAttributes = passioIDAttributes.children.map(
    async ({ passioID }) => {
      return PassioSDK.getAttributesForPassioID(passioID);
    }
  );
  const siblingAttributes = passioIDAttributes.siblings.map(
    async ({ passioID }) => {
      return PassioSDK.getAttributesForPassioID(passioID);
    }
  );
  const parentAttributes = passioIDAttributes.parents.map(
    async ({ passioID }) => {
      return PassioSDK.getAttributesForPassioID(passioID);
    }
  );

  const combinedAttributes = [
    ...childrenAttributes,
    ...siblingAttributes,
    ...parentAttributes,
  ];

  const attrs = await Promise.all(combinedAttributes);
  return attrs.filter(notEmpty);
}

Yeah. Added Quick Scan.

Result

PreviousSearch Food ItemNextMulti Scan

Last updated 1 year ago