4 min read

Smart grocery list

Three weeks ago, Apple held their annual developer conference, WWDC. They announced many remarkable things, including Vision Pro. But one thing that caught my attention was a quality-of-life feature I thought I could recreate using React. So I did.

The feature was the auto-categorisation of groceries in the Reminders app, coming in iOS17. In iOS, it works using on-device machine learning ML and transformer models. For us mere mortals less familiar with technical jargon, it’s basically AI that understands the item you’ve added, then applies an appropriate category. This seemed simple enough for me to execute, using the OpenAI API to understand the input and return an appropriate category.

pnpm create vite

For this project, I chose to create a Vite app. This is now considered the correct approach for starting a new React project if not using frameworks like Next.js. My choice was influenced by the fact that everything would be presented in one view, aided by a utility function to handle the API call.

One challenge was steering the API to consistently use the same categories, and not create different names for the same item. To solve this, I asked ChatGPT to generate some categories for me, along with example items for each category. This produced a list of categories for use when classifying inputs and some local data for common items, which helps reduce calls to the API.

You are welcome to peruse the data.json file.

On to the app. When a new item is entered into the input field and submitted, several processes are triggered. If the state is empty when submitting, the system rejects empty additions. If an item already exists in the list, the input is cleared without further action. Otherwise, the process continues, and the entry is passed to another function to determine its category. This function first checks if the item is in the example data. If it is, the item is returned. If it’s not, the API is called to determine the category.

Here is the system prompt for the API:

You are to act as a categorisation system. You will be given an item, and you must categorise it into one of the following topics: “Fruits and vegetables”, “Dairy and eggs”, “Meat and poultry”, “Fish and seafood”, “Grains, pasta, and rice”, “Breads and bakery”, “Canned and jarred goods”, “Frozen foods”, “Snacks and sweets”, “Condiments and sauces”, “Spices and seasonings”, “Beverages”, “Breakfast items”, “Deli and prepared foods”, “Cooking oils and fats”, “Baking supplies”, “Health foods and supplements”, “Baby and toddler products”, “Pet food and supplies”, “Household and cleaning products”, “Personal care items”, “Office supplies”, “Other”. Only ever use the categories listed above, in the format listed above. Never respond with a category that is not listed above. If you are unsure, respond with simply: “Other”.

You can view the complete fetch here.

The response is then sent back, saved in the new item, and appended to the full list.

That’s the gist of it, though there are a few more implementation details I won’t cover here. However, the repository is public, so check it out if you’re interested.

The tech stack used includes:

  • Vite
  • React
  • Open AI
  • Zustand
  • Framer Motion
  • Tailwind CSS

If I were to use this in a production setting, here are a few changes/additions I’d consider:

  • Ensure the entry is indeed a grocery item—currently, it would just be categorised as “other”
  • Implement checks for and handling of inappropriate language
  • Add toast notifications to help users better understand rejections, etc.
  • Add a button to clear the list
  • Add a button to clear the input