# Project export: NutriSlug

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2024
- Tagline: Generate, track, and plan nutritious and healthy dining hall meals to ensure that no crumb ever goes to waste!
- Devpost: https://devpost.com/software/nutrislug
- GitHub: https://github.com/LucianoLL/cruzhacks_2024_key_caps
- Team: 4 GitHub contributor(s) — Michael Alaniz (9 commits), Rudy Chavez (7 commits), Luciano Loma Lorenzana (6 commits), kdelmo1 (1 commits)

## Devpost submission (written by the team)

### Inspiration

Every member of our team has a story about struggling and working towards improving our overall physical well-being. When we decided it was time to pursue a better life through our health, we naturally had to consider our nutrition and food consumption habits. However, upon arriving at UCSC, we noticed a greater difficulty in maintaining a healthy diet. In addition to the inconsistent dining hall food, the web application displaying the available foods and their nutrition facts was incredibly difficult to navigate and use to track our calorie and macronutrient consumption. Hence, at this year's CruzHacks hackathon, we decided it was time to take matters into our own hands and build a better webpage. What It Does From the UCSC Dining Hall Menus website (https://nutrition.sa.ucsc.edu/), our web application obtains the available food from each dining hall and its nutrition information (calories, protein, carbohydrates, and fat) and generates possible meal options using AI and adjusts suggestions based on previously selected options and user information such as dietary restrictions. How We Built It We used a shared GitHub repository and a stack consisting of Python and React.js. We used Python for web-scraping and AI processing + generation and React.js for all front-end displays and processes. Challenges We Ran Into We found it difficult to handle the size of the web-scrape payload, choosing what to discard or add, and how to optimize its performance given the large amounts of data we were attempting to obtain on and the number of requests we had to send to the UCSC Menus' website. We also found it difficult to connect the back and front ends of our application since we were unfamiliar with fusing the languages that we knew. Accomplishments That We're Proud Of We are proud that we were able to develop a working web scraper with Python that would convert a day's worth of dining hall menus into a readable .json file that our AI could understand and process. We were also proud of the AI itself, seeing as it was made completely from scratch, giving us full customization and saving us resources on unnecessary processes. What We Learned We learned how to work with other team members who possessed a diverse and different set of experiences and knowledge. We also enhanced our ability and skills in machine learning and web development. What's Next for NutriSlug? We plan to continue developing our AI algorithm, enhancing the scale and optimizing the performance of the web application, and seeking out our first clients, possible investors, and prospective mentors.

## README (from the GitHub repository)

# cruzhacks_2024_key_caps

## Detected evidence (automated analysis)

Indexed codebase: 44 recognized source files, 124 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code

## Codebase structure (from repository index)

### Files (57 of 57)

```
.DS_Store
.idea/.gitignore
.idea/cruzhacks_2024_key_caps.iml
.idea/inspectionProfiles/profiles_settings.xml
.idea/misc.xml
.idea/modules.xml
.idea/rSettings.xml
.idea/vcs.xml
backend/AImodel/food_items11.json
backend/AImodel/food_items12.json
backend/AImodel/food_items3.json
backend/AImodel/food_items4.json
backend/AImodel/food.json
backend/AImodel/foodPlate.py
backend/AImodel/menuItem.py
backend/AImodel/plateGeneratorAI.py
backend/AImodel/testingFile.py
backend/AImodel/TestList.py
clientWrapper.py
dh_headers.py
frontend/.gitignore
frontend/food.json
frontend/package.json
frontend/public/index.html
frontend/public/manifest.json
frontend/public/robots.txt
frontend/README.md
frontend/src/App.css
frontend/src/App.js
frontend/src/App.test.js
frontend/src/Components/Icons/AlcoholIcon.js
frontend/src/Components/Icons/BeefIcon.js
frontend/src/Components/Icons/EggIcon.js
frontend/src/Components/Icons/Fish.js
frontend/src/Components/Icons/GlutenIcon.js
frontend/src/Components/Icons/HalalIcon.js
frontend/src/Components/Icons/MilkIcon.js
frontend/src/Components/Icons/PeanutIcon.js
frontend/src/Components/Icons/PorkIcon.js
frontend/src/Components/Icons/SesameIcon.js
frontend/src/Components/Icons/ShellfishIcon.js
frontend/src/Components/Icons/SoyIcon.js
frontend/src/Components/Icons/TreeNutIcon.js
frontend/src/Components/Icons/VeganIcon.js
frontend/src/Components/Icons/VegetarianIcon.js
frontend/src/Components/Navbar.js
frontend/src/index.css
frontend/src/index.js
frontend/src/Pages/BreakfastPage.js
frontend/src/Pages/DinnerPage.js
frontend/src/Pages/HomePage.js
frontend/src/Pages/LunchPage.js
frontend/src/reportWebVitals.js
frontend/src/setupTests.js
frontend/tailwind.config.js
nutrislug_web_scraping.py
README.md
```

### Dependencies

- frontend/package.json: @emotion/react@^11.11.3, @emotion/styled@^11.11.0, @mui/icons-material@^5.15.5, @mui/material@^5.15.5, @svgr/webpack@^8.1.0, @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, openai@^4.25.0, react@^18.2.0, react-dom@^18.2.0, react-router-dom@^6.21.3, react-scripts@^5.0.1, tailwindcss@^3.4.1, web-vitals@^2.1.4

### Recent commits (newest first)

- Fixed plateGeneratorAI.py and added sample output
- updates
- ui
- Merge pull request #8 from LucianoLL/Luciano
- Deleted an unecessary file
- Deleted an unecessary file
- Got the code working to generate meals
- Got the code working to generate meals
- Pushing just in case
- Made some comments on the code
- Starting to work on the model
- Created the filtering system for menu items
- Organizing files
- Merge pull request #7 from LucianoLL/Rudy
- Syncing data
- Added macros
- Merge pull request #6 from LucianoLL/Luciano
- Update a few of the class objects
- Merge pull request #5 from LucianoLL/Rudy
- plate tests setup

## Key source files (fetched from GitHub, selected and truncated for size)

### frontend/package.json

```
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@emotion/react": "^11.11.3",
    "@emotion/styled": "^11.11.0",
    "@mui/icons-material": "^5.15.5",
    "@mui/material": "^5.15.5",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "openai": "^4.25.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "^5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@svgr/webpack": "^8.1.0",
    "react-router-dom": "^6.21.3",
    "tailwindcss": "^3.4.1"
  }
}

```

### frontend/src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### frontend/src/App.js

```javascript
import React from 'react';
import { ReactDOM } from 'react-dom';
import { BrowserRouter as Router, Routes, Route, BrowserRouter } from 'react-router-dom';
import {ThemeProvider } from '@emotion/react';
import { createTheme } from '@mui/material';
import logo from './logo.svg';
import './App.css';
import HomePage from './Pages/HomePage';
import BreakfastPage from './Pages/BreakfastPage';
import DinnerPage from './Pages/DinnerPage';
import LunchPage from './Pages/LunchPage';
import Navbar from './Components/Navbar';

export default function App() {
  
  const theme = createTheme({
    typography:{
      fontFamily: 'Poppins'
      
    }

  })
  
  return (
    <>
      <ThemeProvider theme={theme}>
      <BrowserRouter>
        <Routes> 
          <Route index element = {<HomePage/>}/>
          <Route path='/breakfast' element = {<BreakfastPage/>}/>
          <Route path='/dinner' element = {<DinnerPage/>}/>
          <Route path ='/lunch' element={<LunchPage/>}/>

        </Routes>
    </BrowserRouter>
    </ThemeProvider>
    </>

  );
}


```

### clientWrapper.py

```python
import nutrislug_web_scraping as nws
import backend.AImodel.plateGeneratorAI as pgai

nws.testFcn()
pgai.inputFcn()

```

### nutrislug_web_scraping.py

```python
import asyncio
import aiohttp
import re
import json
from bs4 import BeautifulSoup
from dh_headers import headers, urls
from datetime import date

# List of meals and macronutrients
MEALS = ["Breakfast", "Lunch", "Dinner"]
MACROS = ["Protein", "Total Fat", "Tot. Carb"]

# Regex expression for getting calories
regex_cals = r"(\d+)"

# Regex expression for getting the macro amounts
regex_macros = r"(\d+.\d?.*)"

# Getting today's date for url_add_on
today = date.today()
date_url = today.strftime("%m %d %y").split(" ")
url_add_on = "&WeeksMenus=UCSC+-+This+Week%27s+Menus&dtdate={}%2f{}%2f{}".format(
    date_url[0], date_url[1], date_url[2]
)


# Function to asynchronously get a singular food item's data
async def fetch_food_data(session, url, headers):
    async with session.get(url, headers=headers) as response:
        if response.status == 200:
            fi_soup = BeautifulSoup(await response.text(), "lxml")

            # Getting the macro nutrients
            macro_data = {}
            td_data = fi_soup.find_all("td")
            for td in td_data:
                font_tags = td.find_all("font")
                if len(font_tags) == 2:
                    for m in MACROS:
                        if m in str(font_tags[0]):
                            amount = (
                                re.search(regex_macros, str(font_tags[1])).group(0)
                            )[3:-8]
                            macro_data[m] = amount

            # Getting the name of the food item
            food_name = str(fi_soup.find("div", class_="labelrecipe"))[25:-6]

            # Getting the calories
            b_tags = fi_soup.find_all("b")
            b_tags = [str(b) for b in b_tags]

            calories = "".join([s for s in b_tags if "Calories" in s])
            calories = re.search(regex_cals, calories).group(0)
            if int(calories) == 0:
                return None

            # Getting the allergens
            allergens = fi_soup.find_all("img")
            allergen_list = [str(allergen).split('"')[1] for allergen in allergens]

            return {
                "name": food_name,
                "calories": calories,
                "allergens": allergen_list,
                "macros": macro_data,
            }
        else:
            print(f"Failed to fetch the page. Status code: {response.status}")
            return None


# Function to asynchronously get the menu data
async def fetch_and_process_menu_data(
    session, dh, meal, urls, url_add_on, headers, menu_json
):
    menu_json[dh][meal] = []
    dh_meal_url = urls[dh] + url_add_on + f"&mealName={meal}"

    async with session.get(dh_meal_url, headers=headers[dh]) as long_menu:
        if long_menu.status == 200:
            lm_soup = BeautifulSoup(await long_menu.text(), "lxml")
            all_day_tag = lm_soup.find(
                "div", class_="longmenucolmenucat", string="-- All Day --"
            )
            if all_day_tag:
                href_tags = [a.get("href") for a in all_day_tag.find_all_previous("a")]
            else:
                href_tags = [a.get("href") for a in lm_soup.find_all("a")]

            tasks = []
            for href in href_tags:
                if href and "label.aspx" in href:
                    food_item_url = "https://nutrition.sa.ucsc.edu/" + href
                    tasks.append(fetch_food_data(session, food_item_url, headers[dh]))

            food_items = await asyncio.gather(*tasks)
            menu_json[dh][meal].extend(item for item in food_items if item)
        else:
            print(f"Failed to fetch the page. Status code: {long_menu.status}")


async def main():
    menu_json = {}

    async with aiohttp.ClientSession() as session:
        tasks = []
        for dh in headers.keys():
            menu_json[dh] = {}
            for meal in MEALS:
                tasks.append(
                    fetch_and_process_menu_data(
                        session, dh, meal, urls, url_add_on, headers, menu_json
                    )
                )
        await asyncio.gather(*tasks)

    with open("../backend/AIModel/food.json", "w") as outfile:
        json.dump(menu_json, outfile)


if __name__ == "__main__":
    asyncio.run(main())


def testFcn():
    asyncio.run(main())

```

### dh_headers.py

```python
# File to specify the correct headers for each of the dining halls

# Dictionary which contains each of the headers
headers = dict()

# Dictionary which contains each of the URLs
urls = dict()

# Headers for Crown/Merill DH
headers[20] = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
    'Cookie': 'WebInaCartDates=; WebInaCartMeals=; WebInaCartRecipes=; WebInaCartQtys=; WebInaCartLocation=20',
    'Host': 'nutrition.sa.ucsc.edu',
    'Referer': 'https://nutrition.sa.ucsc.edu/shortmenu.aspx?sName=UC+Santa+Cruz+Dining&locationNum=20&locationName=Crown%2fMerrill+Dining+Hall&naFlag=1',
    'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    'Sec-Ch-Ua-Mobile': '?0',
    'Sec-Ch-Ua-Platform': '"macOS"',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}

# Headers for Nine/Ten DH
headers[40] = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
    'Cookie': 'WebInaCartDates=; WebInaCartMeals=; WebInaCartRecipes=; WebInaCartQtys=; WebInaCartLocation=20',
    'Host': 'nutrition.sa.ucsc.edu',
    'Referer': 'https://nutrition.sa.ucsc.edu/shortmenu.aspx?sName=UC+Santa+Cruz+Dining&locationNum=40&locationName=College+Nine%2fJohn+R.+Lewis+Dining+Hall&naFlag=1',
    'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    'Sec-Ch-Ua-Mobile': '?0',
    'Sec-Ch-Ua-Platform': '"macOS"',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'    
}

# Headers for Porter/Kresge DH
headers[25] = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
    'Cookie': 'WebInaCartDates=; WebInaCartMeals=; WebInaCartRecipes=; WebInaCartQtys=; WebInaCartLocation=20',
    'Host': 'nutrition.sa.ucsc.edu',
    'Referer': 'https://nutrition.sa.ucsc.edu/shortmenu.aspx?sName=UC+Santa+Cruz+Dining&locationNum=25&locationName=Porter%2fKresge+Dining+Hall&naFlag=1',
    'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    'Sec-Ch-Ua-Mobile': '?0',
    'Sec-Ch-Ua-Platform': '"macOS"',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'      
}

# Headers for Oakes/RCC DH
headers[30] = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
    'Cookie': 'WebInaCartDates=; WebInaCartMeals=; WebInaCartRecipes=; WebInaCartQtys=; WebInaCartLocation=20',
    'Host': 'nutrition.sa.ucsc.edu',
    'Referer': 'https://nutrition.sa.ucsc.edu/shortmenu.aspx?sName=UC+Santa+Cruz+Dining&locationNum=30&locationName=Rachel+Carson%2fOakes+Dining+Hall&naFlag=1',
    'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    'Sec-Ch-Ua-Mobile': '?0',
    'Sec-Ch-Ua-Platform': '"macOS"',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'    
}

# Headers for Cowell/Stevenson DH
headers[5] = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
    'Cookie': 'WebInaCartDates=; WebInaCartMeals=; WebInaCartRecipes=; WebInaCartQtys=; WebInaCartLocation=20',
    'Host': 'nutrition.sa.ucsc.edu',
    'Referer': 'https://nutrition.sa.ucsc.edu/shortmenu.aspx?sName=UC+Santa+Cruz+Dining&locationNum=05&locationName=Cowell%2fStevenson+Dining+Hall&naFlag=1',
    'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    'Sec-Ch-Ua-Mobile': '?0',
    'Sec-Ch-Ua-Platform': '"macOS"',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'        
}

# URL for Crown/Merill DH
urls[20] = "https://nutrition.sa.ucsc.edu/longmenu.aspx?sName=UC+Santa+Cruz+Dining&locationNum=20&locationName=Crown%2fMerrill+Dining+Hall&naFlag=1"

[truncated — 722 more characters]
```

### .idea/rSettings.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="RSettings" path="" />
</project>
```

### frontend/tailwind.config.js

```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

### .idea/vcs.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
  </component>
</project>
```

### .idea/misc.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8" project-jdk-type="Python SDK" />
</project>
```

[33 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]