# Project export: Remi: AI Chef

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: Cal Hacks 11.0
- Tagline: Your personalized cooking assistant for ingredient swaps, dietary tips, and effortless meal prep—tailored to your health, powered by AI.
- Devpost: https://devpost.com/software/remi-ai-chef
- GitHub: https://github.com/nilly-willy/hackertime/
- Demo: https://www.figma.com/proto/CS14yGDpzLNZGH7LK3Zb8e/Untitled?page-id=31%3A262&node-id=31-263&node-type=frame&viewport=459%2C111%2C1&t=6YRJbcjO5ZT6XVVl-1&scaling=scale-down&content-scaling=fixed&starting-point-node-id=31%3A263
- Video: https://www.youtube.com/embed/VGx-oxdsaxQ?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Kritika Pantha (16 commits), Nilasha K (11 commits), Amrita Vinjamury (11 commits)

## Devpost submission (written by the team)

### Inspiration

Remi: AI chef was born out of our passion for cooking and trying new recipes, which for all three of us, has been a way to share our culture and our love with the people we love. We decided to create a tool that lets users customize recipes according to their dietary restrictions, medical conditions, and other preferences, allowing them to enjoy the food they love while making the best choices for their well being.

### What it does

Remi harnesses Groq.ai’s powerful AI Inference technology to find ingredient substitutions for recipes submitted by the user. With a series of queries to the LLM models, Remi provides users with alternative ingredients for a wide range of dietary restrictions, as well as medically-informed suggestions for items to omit or include to support patient’s health according to specific conditions, analysis of their protein goals, and scaled quantities according to their requested serving size.

### Challenges we ran into

A challenge faced along the way was deciding the appropriate AI models with the many options offered by Groq.ai and other potential tools, however, we conducted an analysis of prompts across the models, which allowed us to select one that not only provides most accurate results, but also presents in a tone that is appropriate for our app.

### Accomplishments we're proud of

We are especially proud of our successful integration of Groq.ai's AI tool into our technology, which enabled us to provide medically accurate information about the ingredients in users' recipes. This implementation not only improved the overall user experience by offering health-conscious insights but also demonstrated the practical application of AI in everyday contexts such as nutrition and wellness.

### What we learned

During this process, we improved our ability to construct precise and effective prompts for the AI models which was crucial to providing quality information for our users. Integrating Groq.ai into our web application required us to sharpen both our backend and frontend development skills, as we needed to efficiently handle API requests and present our information in an easily digestible format to the end user.

### What's next

We hope to continue this project and focus on improving our AI prompts, optimization, and continuing to develop our Ratatouille themed User Interface to create a robust Recipe and Cooking application that allows every user to feel like a chef!

## README (from the GitHub repository)

To learn more about our project and check out our demo, click this link: https://devpost.com/software/remi-ai-chef 


## Detected evidence (automated analysis)

Indexed codebase: 23 recognized source files, 35 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Flask (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (32 of 32)

```
.DS_Store
.gitignore
backend/.DS_Store
backend/agents/private_keys.json
backend/groq_recipe.py
package.json
private_keys.json
README.md
recipe-app/.gitignore
recipe-app/package.json
recipe-app/public/index.html
recipe-app/public/manifest.json
recipe-app/README.md
recipe-app/src/App.js
recipe-app/src/App.test.js
recipe-app/src/components/embedPage.js
recipe-app/src/components/finalSubmit.js
recipe-app/src/components/HomePage.js
recipe-app/src/components/loading.js
recipe-app/src/components/mainForm.js
recipe-app/src/components/mainInput.js
recipe-app/src/components/navbar.js
recipe-app/src/components/nextButton.js
recipe-app/src/components/output.js
recipe-app/src/components/progress.js
recipe-app/src/components/proteinGoals.js
recipe-app/src/components/scaling.js
recipe-app/src/index.css
recipe-app/src/index.js
recipe-app/src/Navbar.css
recipe-app/src/reportWebVitals.js
recipe-app/src/setupTests.js
```

### Dependencies

- package.json: primeicons@^7.0.0, primereact@^10.8.4, react-router-dom@^6.27.0
- recipe-app/package.json: @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, react@^18.3.1, react-dom@^18.3.1, react-router-dom@^6.27.0, react-scripts@5.0.1, web-vitals@^2.1.4

### Recent commits (newest first)

- Create README.md
- final project
- merging
- final touches
- removing final button
- message
- final one almost raaah'
- port fixes for mac
- newest changes with ui
- css files
- index1.css
- merging home
- home page iter 1
- yur
- merges fixed
- next button fixed
- merge conflict fixed
- fixed next button
- fixed next button
- merge fixed

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

### package.json

```
{
  "dependencies": {
    "primeicons": "^7.0.0",
    "primereact": "^10.8.4",
    "react-router-dom": "^6.27.0"
  }
}

```

### recipe-app/package.json

```
{
  "name": "recipe-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.27.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"
    ]
  }
}

```

### recipe-app/src/App.js

```javascript
// import ReactDOM from "react-dom/client";
// import { BrowserRouter, Routes, Route } from "react-router-dom";
// import { Outlet } from 'react-router-dom';

// // import components
// import FirstPage from './components/firstPage'; 
// import MainForm from './components/mainForm';
// import Progress from './components/progress';

// function Layout() {
//     return (
//       <div>
//         <h1>REMI</h1>
//         <Outlet /> {/* Render child routes here */}
//       </div>
//     );
// }

// export default function App() {
//   return (
//     <BrowserRouter>
//       <Routes>
//         {/* Set Layout as the base route */}
//         <Route path="/" element={<Layout />}>
//           {/* Use 'index' for the default page */}
//           <Route index element={<FirstPage />} />
//           <Route path="form" element={<MainForm />} />
//           <Route path="progress" element={<Progress />} />
//         </Route>
//       </Routes>
//     </BrowserRouter>
//   );
// }

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

```

### recipe-app/src/index.js

```javascript
import ReactDOM from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Outlet } from 'react-router-dom';

// import components
import MainForm from './components/mainForm';
import ScalingInput from './components/scaling'
import ProteinGoalInput from './components/proteinGoals';
import FinalSubmitButton from './components/finalSubmit';
import MainInput from "./components/mainInput";
import EmbedPage from "./components/embedPage";
import Loading from "./components/loading";
import Output from "./components/output";
import Navbar from "./components/navbar";
import HomePage from './components/HomePage'; 

function Layout() {
  return (
    <div>
      <Navbar />
      <Outlet />
    </div>
  );
}

export default function App() {
return (
  <BrowserRouter>
    <Routes>
      {/* Set Layout as the base route */}
      <Route path="/" element={<Layout />} >
        {/* Use 'index' for the default page */}
        <Route index element={<HomePage />} />
        <Route path="input" element={<MainInput />} />
        <Route path="embed" element={<EmbedPage />} />
        <Route path="form" element={<MainForm />} />
        <Route path="protein" element={<ProteinGoalInput />} />
        <Route path="scale" element={<ScalingInput />} />
        <Route path="load" element={<Loading />} />
        <Route path="output" element={<Output />} />
      </Route>
    </Routes>
  </BrowserRouter>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);

// reportWebVitals();

```

### backend/groq_recipe.py

```python
import os
from groq import Groq
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin
import json 

# app = Flask(__name__)
# CORS(app)
app = Flask(__name__)
CORS(app)

client = Groq(
    api_key="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",
)


# extracting ingredients from recipe
def get_ingredients(user_input_recipe):
    get_ingredients = client.chat.completions.create(
        messages=[
            {
  "role": "user",
  "content": f"""Please extract the ingredients and their corresponding quantities, 
  including measurements (e.g., cups, grams, teaspoons, etc.), from the following 
  recipe: {user_input_recipe}. Ensure to list each ingredient on a new line."""
}

        ],
        model="llama3-8b-8192",
    )
    get_ingredients_output = get_ingredients.choices[0].message.content
    print(get_ingredients.choices[0].message.content)
    return get_ingredients_output

# scaling ingredients based on user defined serving size
def scaling_ingredients(ingredients, scaling_factor):
    if scaling_factor == 1:
        return ingredients
    else:
        scaling = client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": f"""Given the following ingredient quantities: {ingredients}, please multiply each quantity by a factor of {scaling_factor}. 
                Return only the new ingredient quantities without showing any calculations or the original amounts."""
                }
            ],
            model="llama3-8b-8192",
        )
        #print(scaling.choices[0].message.content)
        scaling_output = scaling.choices[0].message.content
        return scaling_output

# food restrictions
def food_restrictions(scaled_ingredients, food_restrictions):
    if food_restrictions == []:
        return scaled_ingredients
    else:
        restrictions = client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": f"""Please adjust the following ingredient list: {scaled_ingredients} to comply with these food restrictions: {food_restrictions}. 
                Ensure that all modifications are suitable and clearly indicate any changes made to the ingredients."""
                }
            ],
            model="llama3-8b-8192",
        )
        #print(restrictions.choices[0].message.content)
        restrictions_output = restrictions.choices[0].message.content
        return restrictions_output

# health issue modifications
def health_modifications(altered_ingredients, health_issues, food_restrictions):
    if health_issues == []:
        return altered_ingredients
    else:
        health_modifications = client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": f"""Given these health issues: {health_issues}, modify my ingredients and/or quantities to address these
                    health concerns. Here is a list of my ingredients: {altered_ingredients}. Please ensure the modified recipe considers the following:
                    Limit or remove ingredients that exacerbate these health issues.
                    Suggest suitable substitutions for ingredients if necessary.
                    Ensure the recipe remains balanced, flavorful, and enjoyable.
                    Return a list of modified ingredients. Make sure these modifications do not class with these food restrictions: {food_restrictions}. 
                    If they do, find alternatives"""
                }
            ],
            model="llama3-8b-8192",
        )
        #print(health_modifications.choices[0].message.content)
        modifications_output = health_modifications.choices[0].message.content
        return modifications_output

# protein goal modifications
def protein_goals(modified_ingredients, protein_goal):
    if protein_goal == 0:
        return modified_ingredients
    else:
        protein_goals = client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": f"""Adjust the following ingredients: {modified_ingredients} to help me achieve my protein goal of {str(protein_goal)} grams for this meal. 
                Please specify any changes made to the ingredient quantities to meet the protein requirement."""
                }
            ],
            model="llama3-8b-8192",
        )
        #print(restrictions.choices[0].message.content)
        protein_modified = protein_goals.choices[0].message.content
        return protein_modified

# final modified recipe
def new_recipe(new_ingredients, original_user_input):

    final_recipe = client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": f"""Here is the original recipe: {original_user_input}. Please replace the ingredients with my modified ones: {new_ingredients}. 
                Format the response so that the ingredients and their quantities are listed first, with each ingredient on a new line. 
                After the ingredients, include each step of the recipe on a new line as well. Return the newly modified recipe in this format."""
                }
            ],
            model="llama3-8b-8192",
        )
        #print(restrictions.choices[0].message.content)
    final_output = final_recipe.choices[0].message.content
    return final_output

original_recipe = ""
modified_ingredients = ""
scaling_factor = 2
food_restriction = "vegetarian"
health_problems = "high cholesterol"
protein_goal = 30

app = Flask(__name__)
CORS(app)

@app.route('/')
def index():
    return "intializing..."

@app.route('/api/process_input', methods=['POST', 'OPTIONS'])
def process_input():
    if request.method == 'OPTIONS':
        return jsonify({'status': 'success'}), 200
    data = request.get_json()
   
[truncated — 3689 more characters]
```

### recipe-app/src/setupTests.js

```javascript
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

```

### recipe-app/src/App.test.js

```javascript
/** import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
}); */

```

### recipe-app/src/reportWebVitals.js

```javascript
const reportWebVitals = onPerfEntry => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;

```

### recipe-app/public/index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Sarpanch">
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

```

### recipe-app/src/index.css

```css
/* HOME PAGE STYLING */

/* Wrapper should take full viewport height and allow scrolling */
.homepage-wrapper {
  width: 100%;
  min-height: 100vh; /* Full viewport height */
  background: white;
  display: flex;
  flex-direction: column;
  overflow-y: auto; /* Ensure vertical scrolling */
}
.ai-chef-heading {
  font-family: 'Sarpanch', sans-serif; /* Use the Sarpanch font */
  text-align: center; /* Center the text */
  font-size: 3rem; /* Adjust size as needed */
  margin: 20px 0; /* Add some space above and below */
  color: #333; /* Change color if desired */
}


/* Photo Grid */
.photo-grid {
  display: grid;
  grid-template-columns: 3fr, 3fr;
  grid-gap: 5px;
  padding: 15px;
  justify-items: center;
}

/* Grid item styling */
.photo-grid-item {
  border-radius: 15px;
  object-fit: cover;
  width: 80%;
  height: auto;
  box-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
}

/* Upload Recipe Button */
.upload-recipe-button-container {
  text-align: center;
  margin-top: 20px;
}

.upload-recipe-button {
  background: linear-gradient(90deg, #FBB4B4 0%, #FFA65D 100%);
  box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.25);
  border-radius: 35.27px;
  padding: 10px 50px;
  font-family: 'Sarpanch', sans-serif;
  font-size: 20px;
  font-weight: 700;
  color: black;
  border: 2px solid black;
}

/* Headings */
.heading-1 {
  font-family: 'Sarpanch', sans-serif;
  font-size: 24px;
  font-weight: 700;
  text-align: center;
  color: black;
  margin-top: 30px;
}

```

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