Constructing a Meals Stock Administration App – DZone – Uplaza

Lately, eating places, meals banks, dwelling kitchens, and some other enterprise that offers with merchandise and meals that go dangerous shortly must have good meals stock administration. Kitchens keep organized and waste is stored to a minimal by holding observe of inventory, checking expiration dates, and managing utilization nicely.

I’ll present you make a Meals Stock Administration App on this information. With this app, customers can:

  1. Add meals objects or elements to the stock.
  2. Monitor the amount of every merchandise.
  3. Take away objects once they’re used or expired.
  4. Optionally, generate recipes or recommend makes use of for the objects.

The Meals Stock Administration App is not going to solely observe meals objects but additionally generate recipes based mostly on the accessible elements utilizing a Hugging Face mannequin. I’ll use Subsequent.js for the entrance finish, Materials-UI for the consumer interface, Firebase Firestore for real-time database performance, and a Hugging Face mannequin for recipe era.

Setting Up the Surroundings for Improvement

We have to arrange our working surroundings earlier than we begin writing code for our Meals Stock Administration App.

1. Set up Node.js and npm

Step one is to put in Node.js and npm. Go to the Node.js web site and get the Lengthy Time period Assist model to your pc’s working system. Comply with the steps given for set up.

2. Making a Venture With Subsequent.js

Begin up your terminal and go to the situation the place you wish to make your undertaking. After that, run these instructions:

  • npx create-next-app@newest food-inventory-management-app (With the @newest flag, npm will get the newest model of the Subsequent.js beginning setup.)
  • cd food-inventory-management-app

It should make a brand new Subsequent.js undertaking and take you to its path. You will be given a lot of configuration selections in the course of the setup course of, set them as given beneath:

  • Would you want to make use of TypeScript? No
  • Would you want to make use of ESLint? Sure
  • Would you want to make use of Tailwind CSS? No
  • Would you want to make use of the src/ listing? No
  • Would you want to make use of App Router? Sure
  • Would you wish to customise the default import alias? No

3. Putting in Firebase and Materials-UI

Within the listing of your undertaking, execute the next command:

  • npm set up @mui/materials @emotion/react @emotion/styled firebase

Setting Up Firebase

  • Launch a brand new undertaking on the Firebase Console.
  • Click on “Add app” after your undertaking has been constructed, then select the net platform (>).
  • Give your app a reputation while you register it, equivalent to “Food Inventory Management App.”
  • Make a duplicate of the Firebase setup file. Afterwards, this might be helpful.

4. Create a Firebase Configuration File

Make a brand new file known as firebase.js within the root listing of your undertaking and add the next code, changing the placeholders with the true Firebase settings to your undertaking:

import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_PROJECT_ID.appspot.com",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID"
 };

const app = initializeApp(firebaseConfig);

const db = getFirestore(app);

export { db };

Constructing a Flask API for Recipe Era Utilizing Hugging Face

I am going to present you make a Flask-based API that makes use of a Hugging Face mannequin to make recipes. With a POST request, customers will be capable of ship elements to the API. It should then use a pre-trained mannequin from Hugging Face to return a recipe based mostly on these elements. We’ll use surroundings variables to soundly deal with Hugging Face tokens.

1. Setting Up the Python Surroundings

  • Set up Python if not already current (brew set up python).
  • Confirm set up (python3 --version).
  • Set up dependencies (pip set up Flask flask-cors transformers huggingface_hub).

2. Setting Up the Hugging Face Token

  • Go to the Hugging Face web site.
  • If you have already got an account, click on on Signal In. If not, click on Signal Up to create a brand new account.
  • Navigate to the dropdown menu, and choose Settings.
  • Within the Settings menu, search for the Entry Tokens tab on the left aspect of the web page and click on on it.
  • Beneath the Entry Tokens part, you will note a button to create a brand new token. Click on on New Token.
  • Give your token a descriptive identify (e.g., “Food Inventory App Token”).
  • Select Learn because the token scope for primary entry to fashions and datasets. In case you want write entry for importing fashions or knowledge, select Write.
  • Click on Generate Token. The token might be displayed on the display screen.
  • After producing the token, copy it. Be certain that to put it aside in a safe place, as you have to it for authentication when making API calls.

3. Preserving Hugging Face API Token Protected

Your Hugging Face API token must be stored safely in an surroundings variable as a substitute of being written in your script as code. To do that:

  • Create an .env file within the root of your undertaking: (contact .env).
  • Inside this file, add your Hugging Face token (HF_TOKEN=your_hugging_face_token_here).
  • Load this surroundings variable securely in your Flask app utilizing Python’s os module.
import os
huggingface_token = os.getenv('HF_TOKEN')

4. Constructing the Flask API

Flask app with Hugging Face’s recipe era mannequin (notice: this pattern mannequin is free). Title the file as backend.py.

import os
from flask import Flask, request, jsonify
from flask_cors import CORS
from huggingface_hub import login
from transformers import pipeline

app = Flask(__name__)
CORS(app)

# Securely get the Hugging Face token from the surroundings
huggingface_token = os.getenv('HF_TOKEN')
if huggingface_token:
    login(token=huggingface_token)

# Load Hugging Face meals recipe mannequin pipeline
strive:
    model_name = "flax-community/t5-recipe-generation"
    recipe_generator = pipeline("text2text-generation", mannequin=model_name)
besides Exception as e:
    print(f"Error loading model: {e}")
    recipe_generator = None

@app.route('/generate_recipe', strategies=['POST'])
def generate_recipe():
    knowledge = request.json
    print("Hello")
    elements = knowledge.get('elements')
    if not elements:
        return jsonify({"error": "Ingredients not provided."}), 500
    if recipe_generator:
        strive:
            response = recipe_generator(f"Generate a recipe using the following ingredients: {ingredients}")
            return jsonify({"recipe": response[0]['generated_text']})
        besides Exception as e:
            print(f"Error generating recipe: {e}")
            return jsonify({"error": "Error generating recipe"}), 500
    else:
        return jsonify({"error": "Recipe generator model is not available."}), 500

if __name__ == '__main__':
    app.run(debug=True, port=5001)
  • Observe: The flax-community/t5-recipe-generation mannequin is loaded utilizing the Hugging Face pipeline. This mannequin might be utilized to generate recipes utilizing the given/saved elements.

Constructing the Core Parts for the Meals Stock Administration

1. Import All Mandatory Libraries

'use shopper';

import React, { useEffect, useState } from 'react';
import { Field, Stack, Typography, Button, TextField, IconButton, Tabs, Tab } from '@mui/materials';
import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { assortment, addDoc, deleteDoc, doc, onSnapshot, updateDoc, question, the place, getDocs } from 'firebase/firestore';
import { db } from './firebase'; // Firebase configuration
import DeleteIcon from '@mui/icons-material/Delete';
import dayjs from 'dayjs';
import axios from 'axios';

On this step, we arrange our element with the essential format and imports it wants. It is a client-side element, as proven by the 'use shopper' command on the high.

2. Utility Capabilities

# We outline a utility operate that capitalizes the primary letter of a string.
const capitalizeFirstLetter = (string) => string.charAt(0).toUpperCase() + string.slice(1);

3. State Administration and useEffect for Firestore Snapshot

We have to arrange states to maintain observe of pantry objects, new merchandise enter, expiration dates, search queries, energetic tabs, and recipe ideas.

  • objects: Shops pantry objects
  • newItem: Shops the identify of the merchandise to be added
  • expirationDate: Shops the expiration date of the brand new merchandise
  • searchQuery: Shops the search enter for filtering objects
  • tabIndex: Shops the present tab (Accessible, Quickly to Expire, Expired)
  • recipe: Shops the generated recipe

The useEffect hook screens adjustments in Firestore knowledge utilizing the onSnapshot technique, guaranteeing that the pantry objects are at all times updated.

export default operate Pantry() {
  const [items, setItems] = useState([]); 
  const [newItem, setNewItem] = useState(''); 
  const [expirationDate, setExpirationDate] = useState(null); 
  const [searchQuery, setSearchQuery] = useState(''); 
  const [tabIndex, setTabIndex] = useState(0); 
  const [recipe, setRecipe] = useState(''); 

  // Fetch objects from Firestore and replace state in real-time
  useEffect(() => {
    const unsubscribe = onSnapshot(assortment(db, 'pantryItems'), (snapshot) => {
      const itemsList = snapshot.docs.map((doc) => ({
        id: doc.id,
        identify: doc.knowledge().identify,
        amount: doc.knowledge().amount,
        expirationDate: doc.knowledge().expirationDate,
      }));
      setItems(itemsList);
    });
    return () => unsubscribe();
  }, []);

4. Add a New Merchandise to Firestore

This operate is used so as to add a brand new merchandise to the Firestore database. If the merchandise is already current, its amount is elevated. Alternatively, the brand new merchandise might be added with a delegated expiration date.

  // Add a brand new merchandise to Firestore
  const addItemToFirestore = async () => {
    if (newItem.trim() !== '' && expirationDate) {
      const q = question(assortment(db, 'pantryItems'), the place('identify', '==', newItem));
      const querySnapshot = await getDocs(q);

      if (querySnapshot.empty) {
        await addDoc(assortment(db, 'pantryItems'), { identify: newItem, amount: 1, expirationDate: expirationDate.toISOString() });
      } else {
        querySnapshot.forEach(async (doc) => {
          const itemRef = doc(db, 'pantryItems', doc.id);
          await updateDoc(itemRef, { amount: doc.knowledge().amount + 1 });
        });
      }

      setNewItem('');
      setExpirationDate(null);
    }
  };

5. Take away an Merchandise from Firestore or Lower Its Amount

This operate both decreases the amount of an present merchandise or removes the merchandise solely if the amount reaches zero.

  // Take away an merchandise or lower its amount
  const removeItemFromFirestore = async (id) => {
    const itemRef = doc(db, 'pantryItems', id);
    const itemDoc = await getDoc(itemRef);

    if (itemDoc.exists()) {
      const currentQuantity = itemDoc.knowledge().amount;

      if (currentQuantity > 1) {
        await updateDoc(itemRef, { amount: currentQuantity - 1 });
      } else {
        await deleteDoc(itemRef);
      }
    }
  };

6. Fetch Recipe Options From Flask Backend

This operate sends an inventory of obtainable objects and objects which are near their expiration date to the Flask backend for recipe era. The backend generates a recipe and shops it within the recipe state.

  // Fetch recipe ideas utilizing elements
  const fetchRecipeSuggestions = async (availableItems, soonToExpireItems) => {
    const elements = [...availableItems, ...soonToExpireItems].map(merchandise => merchandise.identify).be part of(', ');

    strive {
      const response = await axios.publish('http://127.0.0.1:5001/generate_recipe', { elements });
      setRecipe(response.knowledge.recipe);
    } catch (error) {
      console.error('Error fetching recipe ideas:', error.message);
      setRecipe('Error fetching recipe ideas. Please strive once more later.');
    }
  };

7. Filter and Categorize Objects Based mostly on Expiration

The pantry objects are sorted in accordance with their expiration dates. Three classes might be established: Accessible Objects, Quickly to Expire, and Expired Objects.

  // Filter and categorize objects based mostly on expiration
  const filteredItems = objects.filter((merchandise) => merchandise.identify.toLowerCase().contains(searchQuery.toLowerCase()));
  const soonToExpireItems = filteredItems.filter((merchandise) => dayjs(merchandise.expirationDate).diff(dayjs(), 'day')  dayjs(merchandise.expirationDate).diff(dayjs(), 'day')  !soonToExpireItems.contains(merchandise) && !expiredItems.contains(merchandise));

Constructing the UI Parts for the Meals Stock Administration

  return (
    
      
        {/* Add new pantry merchandise */}
        
          Add Pantry Merchandise
           setNewItem(e.goal.worth)} />
           setExpirationDate(newValue)} />
          
        

        {/* Search and Tabs */}
         setSearchQuery(e.goal.worth)} />
         setTabIndex(newValue)}>
          
          
          
        

        {/* Show Objects */}
        {tabIndex === 0 && availableItems.map((merchandise) => (
          
            {capitalizeFirstLetter(merchandise.identify)} - {merchandise.amount}
             removeItemFromFirestore(merchandise.id)}>
          
        ))}
        {tabIndex === 1 && soonToExpireItems.map((merchandise) => (
          
            {capitalizeFirstLetter(merchandise.identify)} - {merchandise.amount} (Expires: {dayjs(merchandise.expirationDate).format('YYYY-MM-DD')})
             removeItemFromFirestore(merchandise.id)}>
          
        ))}
        {tabIndex === 2 && expiredItems.map((merchandise) => (
          
            {capitalizeFirstLetter(merchandise.identify)} - {merchandise.amount} (Expired: {dayjs(merchandise.expirationDate).format('YYYY-MM-DD')})
             removeItemFromFirestore(merchandise.id)}>
          
        ))}

        {/* Fetch Recipe Options */}
        
        {recipe && {recipe}}
      
    
  );
}

Clarification of UI Parts

1. (Container)

  • Function: Acts as a versatile container for managing format, padding, and alignment
  • Used for: Wrapping sections like the shape, search bar, and merchandise lists

2. (Vertical/Horizontal Structure)

  • Function: Organizes baby parts in a vertical or horizontal format
  • Used for: Structuring type components and merchandise listings with correct spacing

3. (Textual content Show)

  • Function: Renders and types textual content content material
  • Used for: Displaying headings, merchandise names, expiration dates, and recipe ideas

4. (Enter Area)

  • Function: Offers a textual content enter area.
  • Used for: Inputting new pantry merchandise names and search queries

5. (Date Choice)

  • Function: Permits customers to select a date from a calendar
  • Used for: Deciding on expiration dates for pantry objects, built-in with the Day.js adapter

6. (Clickable Button)

  • Function: A clickable button for actions
  • Used for: Including objects to Firestore, fetching recipes, and interacting with the database

7. and (Tab Navigation)

  • Function: Creates a tabbed interface for navigation
  • Used for: Switching between accessible, soon-to-expire, and expired objects

8. (Icon-Based mostly Button)

  • Function: Button with an icon for fast actions.
  • Used for: Deleting or decreasing the amount of things, utilizing a delete icon

9. (Date Localization)

  • Function: Manages date localization and formatting
  • Used for: Making certain appropriate show and dealing with of dates within the date picker

10. (Icon)

  • Function: Shows a delete icon for motion
  • Used for: Indicating delete motion on buttons for merchandise removing

11. Recipe Suggestion Part

  • Function: Shows recipe ideas based mostly on accessible elements
  • Used for: Exhibiting the recipe generated by the Flask API when the “Get Recipe Suggestions” button is clicked

12. (Responsive Structure)

  • Function: Creates responsive layouts with versatile columns.
  • Used for aligning content material: Organizing components like types and buttons inside a structured grid.
  • Dividing UI into columns: Structuring content material into columns and rows for a clear, responsive format on varied display screen sizes.

Operating the Meals Stock Administration Utility

1. Begin the Improvement Server

Navigate to http://localhost:3000 as prompted by opening your browser.

2. Begin the Flask Improvement Server

Begin the Flask Improvement Server together with the beneath.

This can provoke the Flask API at http://127.0.0.1:5001.

Please bear in mind the interplay between React and Flask is finished utilizing Axios to ship HTTP requests and show the leads to actual time.

The Hugging Face mannequin I used is free to make use of. If you wish to use a unique mannequin, like Llama, you are able to do that too.

Pattern Picture of the Meals Stock Administration Utility After Improvement

Conclusion

Congratulations! You could have efficiently developed a purposeful Meals Stock Administration Utility.

Completely happy coding!

Share This Article
Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

Exit mobile version