# Project export: Palate

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: TreeHacks 2024
- Tagline: what's cookin, good lookin?
- Devpost: https://devpost.com/software/palate-nozheb
- GitHub: https://github.com/jmcmai/palate
- Team: 4 GitHub contributor(s) — phuuuc (46 commits), Jenny Mai (38 commits), ngochtran (21 commits), Caroline Van (14 commits)

## Devpost submission (written by the team)

### Inspiration

At the heart of Palate lies a deep-seated appreciation for the connections forged over shared meals. As a team, we've experienced firsthand the magic of gathering around a table, whether it's for cherished family dinners or impromptu meetups with friends. These moments, woven into the fabric of our lives, inspired us to create Palate at Tree Hacks, where our shared passion for food and technology converged. Throughout the weekend, fueled by Popeyes runs and dining hall escapades, we poured our energy into crafting Palate—a testament to the power of collaboration and shared vision. Yet, beyond the lines of code, Palate embodies a philosophy of mindful eating and thoughtful connection. With Palate, we aim to elevate the dining experience by seamlessly integrating personal preferences and dietary restrictions. Gone are the days of cumbersome inquiries about allergies or dislikes; instead, Palate intuitively keeps track, allowing meals to be curated with care and consideration. By prioritizing the well-being and preferences of those we share meals with, we not only foster deeper connections but also create space for moments of genuine enjoyment and appreciation. In a world filled with distractions, Palate serves as a reminder of the importance of mindful living, even in something as seemingly mundane as choosing what to eat. Through this project, we hope to inspire others to embrace the joy of shared meals, where every bite becomes an opportunity for connection and celebration.

### What it does

Palate is a multifaceted platform designed to revolutionize your culinary experience. Here's a closer look at its key features: Personalized Food Journal: Palate serves as your digital food diary, meticulously cataloging your favorite cuisines and dishes. But it goes beyond mere record-keeping, as it also takes into account your dietary restrictions and ingredient preferences. Whether you're avoiding certain foods due to allergies or simply dislike their taste, Palate ensures that your culinary journey is tailored to your unique preferences. Smart Recipe Recommendations: Powered by a robust database, Palate leverages your stored information to offer personalized recipe suggestions. By analyzing your fridge inventory, liked ingredients, disliked ingredients, and dietary restrictions, Palate curates a selection of recipes perfectly suited to your tastes and dietary needs. Say goodbye to endless recipe searches and hello to a curated selection of culinary delights at your fingertips. Dynamic Recipe Retrieval: Unlike static recipe databases, Palate dynamically retrieves recipes from the internet in real-time. This means you'll always have access to a diverse range of recipes, ensuring that your culinary repertoire stays fresh and exciting. Whether you're craving a classic comfort food or eager to experiment with a new culinary trend, Palate has you covered. Interactive Chatbot: Palate takes your culinary experience to the next level with its interactive chatbot feature. Whether you're seeking recipe recommendations, ingredient substitutions, or cooking tips, the Palate chatbot is always ready to assist. But what sets Palate's chatbot apart is its ability to leverage both your chat history and database information to provide personalized assistance. By analyzing past conversations and stored data, the chatbot offers tailored suggestions and insights, ensuring that every interaction is relevant and helpful. Social Event Planning: Palate isn't just about individual culinary exploration—it's also about fostering connections through shared experiences. With its event planning feature, you can create gatherings and invite your friends to join. But Palate doesn't stop there; it takes the hassle out of menu planning by recommending recipes tailored to the preferences of all attendees. From potlucks to dinner parties, Palate ensures that every event is a culinary success. User Authentication: Ensuring that data provided from the user to us, are safe and sound! Fuzzy/error checking for ingredients: Using levenshtein distance, our program chooses ingredients that are best matched to the user's input.

### How we built it

We built Palate using ReactJs as our frontend, Convex as our backend/database. For our chatbot, we used Together AI's Inference models with the Function Calling and JSON mode to structure external API calls from user queries. To query the internet, we used Tavily to perform searches, and Recipe-Scraper (https://github.com/jadkins89/Recipe-Scraper) to scrape the recipe given a url. Our steps for building our recommendation system were: The user can interact with Ramsey (chat bot) and describe dishes, ingredients, and cuisines they are interested in receiving a recipe for. Given a dataset that includes a dishes name, ingredients, and cuisine, we aggregate a user's liked ingredients, disliked ingredients, and cuisines and chat interactions to pinpoint dishes to recommend. We call Tavliy to query the web for recipes matching the dish and diet of the user and get a list of urls. We use a recipe scraper to retrieve the recipes to populate into Ramsey and our events.

### Challenges we ran into

Some challenges that we ran into were: Choosing Datasets: To have Palate recommend us recipes, we first created a dataset of dishes using Recipe NLG (there are two versions, 1M+, lite). For ease of implementation, we chose to use the lite version. We felt it was important to curate to liked cuisines of the users, however, we were not able to find any available datasets on the internet that mapped dishes to cuisines. As a way to work around this, we used Together AI's API calls to categorize a dish by its cuisine based on its name and list of ingredients. We acknowledge that there may be dishes in our dataset that is falsely classified. Chatbot Challenges: Developing the chatbot proved to be a formidable task as we encountered difficulties in prompting it effectively. Despite leveraging data to augment its responses, the chatbot often provided unexpected or strange answers, requiring extensive refinement and debugging. Technical Learning Curve: Navigating the learning curves of Convex and ReactJS presented significant challenges for our team. As most of us were unfamiliar with these tools prior to embarking on the Palate project, we faced a steep learning curve in mastering their intricacies and functionalities. Understanding Asynchronous Programming: Grappling with the concepts of asynchronous programming, including async, await, and promises, posed additional hurdles in the development process. Recognizing the importance of these mechanisms in ensuring smooth and responsive user experiences, we dedicated time to deepen our understanding and implementation proficiency.

### Accomplishments we're proud of

Mastering Convex: Through the development of Palate, we gained invaluable experience in utilizing Convex for user authentication, enhancing our understanding of secure authentication processes within web applications. AI Augmented Data Pipelines: Delving into the creation of pipelines for AI-augmented data retrieval and generation was a transformative learning experience. We honed our skills in integrating AI technologies seamlessly into our platform, empowering Palate to offer intelligent and personalized recommendations to users. Functional Web Application Development: Perhaps most notably, we're proud to have successfully built a functional web application for Palate. From conceptualization to execution, we navigated the complexities of web development, overcoming challenges and refining our skills along the way. Our achievement in bringing Palate to life underscores our growth and proficiency in creating user-centric digital solutions.

### What we learned

Convex which enabled seamless frontend-backend interaction through API calls. Learned about function calling and generation, enhancing the dynamic capabilities of data manipulation within Palate. Transitioned from JavaScript to TypeScript with React, embracing TypeScript's benefits for writing robust and maintainable code in our frontend components.

### What's next

for palate Adding more options for dishes to recommend. Being able to recommend more than one items. Caching recommendations to speed up performances. Introducing new events you can organize such as potlucks, or date night. Through this, you are able to assign yourself/others recipes to cook for your events! Palate blend: see how similar your palate is with your friends!

## README (from the GitHub repository)

# Getting Started with Create React App

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

## Available Scripts

In the project directory, you can run:

### `npm start`

Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.

The page will reload when you make changes.\
You may also see any lint errors in the console.

### `npm test`

Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.

### `npm run build`

Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

### `npm run eject`

**Note: this is a one-way operation. Once you `eject`, you can't go back!**

If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.

You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.

## Learn More

You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).

To learn React, check out the [React documentation](https://reactjs.org/).

### Code Splitting

This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)

### Analyzing the Bundle Size

This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)

### Making a Progressive Web App

This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)

### Advanced Configuration

This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)

### Deployment

This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)

### `npm run build` fails to minify

This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)


## Detected evidence (automated analysis)

Indexed codebase: 56 recognized source files, 118 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
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (65 of 65)

```
.gitignore
convex.json
LICENSE
package.json
public/index.html
public/manifest.json
public/robots.txt
README.md
README.old.md
src/App.css
src/App.test.js
src/App.tsx
src/components/Badge.tsx
src/components/DietaryRestrictionItem.tsx
src/components/DietaryRestrictions.tsx
src/components/DislikedIngredientItem.tsx
src/components/DislikedIngredients.tsx
src/components/EventComponent.tsx
src/components/LikedCuisineItem.tsx
src/components/LikedCuisines.tsx
src/components/LikedIngredientItem.tsx
src/components/LikedIngredients.tsx
src/components/LoginButton.tsx
src/components/LogoutButton.tsx
src/components/Navbar.tsx
src/components/Pantry.tsx
src/components/PantryItem.tsx
src/components/PinnedComponent.tsx
src/components/RecipeComponent.tsx
src/components/Template.tsx
src/convex/_generated/api.d.ts
src/convex/_generated/api.js
src/convex/_generated/dataModel.d.ts
src/convex/_generated/server.d.ts
src/convex/_generated/server.js
src/convex/auth.config.ts
src/convex/dishes.ts
src/convex/events.ts
src/convex/messages.ts
src/convex/recipeRetrievers.ts
src/convex/recipes.ts
src/convex/schema.ts
src/convex/serve.ts
src/convex/tavily.js
src/convex/together.ts
src/convex/tsconfig.json
src/convex/users.ts
src/datasets/create-dataset.py
src/datasets/dishes_dataset.csv
src/index.css
src/index.tsx
src/pages/Chat.css
src/pages/Chat.tsx
src/pages/Events.css
src/pages/Events.tsx
src/pages/Login.css
src/pages/Login.tsx
src/pages/Recipes.css
src/pages/Recipes.tsx
src/pages/Settings.css
src/pages/Settings.tsx
src/reportWebVitals.js
src/setupTests.js
src/useStoreUserEffect.ts
tsconfig.json
```

### Dependencies

- package.json: @auth0/auth0-react@^2.2.4, @fortawesome/fontawesome-svg-core@^6.5.1, @fortawesome/free-solid-svg-icons@^6.5.1, @fortawesome/react-fontawesome@^0.2.0, @langchain/community@^0.0.30, @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, @types/react@^18.2.56, @types/react-dom@^18.2.19, convex@^1.9.0, openai@^4.28.0, react@^18.2.0, react-dom@^18.2.0, react-router-dom@^6.22.1, react-scripts@^5.0.1, recipe-scraper@^2.1.1, typescript@^4, web-vitals@^2.1.4

### Recent commits (newest first)

- Merge branch 'main' of https://github.com/jmcmai/palate
- spruce up events form
- Update Recipes.css
- Recipes page DONE
- Merge pull request #28 from jmcmai/phuc
- added sync palate calls
- Merge branch 'main' of https://github.com/jmcmai/palate
- edits
- Merge branch 'main' of https://github.com/jmcmai/palate
- rewire userId to chat
- Merge pull request #27 from jmcmai/phuc
- emails to id
- emails to id
- Merge branch 'main' of https://github.com/jmcmai/palate
- add chat interface
- Merge pull request #26 from jmcmai/phuc
- get pinned, pantry calls
- Merge pull request #25 from jmcmai/phuc
- added some sync code, updated events schema
- Merge pull request #24 from jmcmai/jenny-branch

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

### README.old.md

```markdown
# palette
what's cookin, good lookin?

```

### package.json

```
{
  "name": "palette",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@auth0/auth0-react": "^2.2.4",
    "@fortawesome/fontawesome-svg-core": "^6.5.1",
    "@fortawesome/free-solid-svg-icons": "^6.5.1",
    "@fortawesome/react-fontawesome": "^0.2.0",
    "@langchain/community": "^0.0.30",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "convex": "^1.9.0",
    "openai": "^4.28.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.22.1",
    "recipe-scraper": "^2.1.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": {
    "@types/react": "^18.2.56",
    "@types/react-dom": "^18.2.19",
    "react-scripts": "^5.0.1",
    "typescript": "^4"
  }
}

```

### src/App.tsx

```typescript
import { BrowserRouter as Router, Routes, Route, useLocation } from "react-router-dom";
import React, { useEffect } from "react";

import Recipes from "./pages/Recipes";
import Login from "./pages/Login";
import Chat from "./pages/Chat";
import Events from "./pages/Events";
import Settings from "./pages/Settings";

import "./App.css";

const ScrollToTop: React.FC = () => {
  const { pathname } = useLocation();

  useEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);

  return null;
};

const App: React.FC = () => {
  return (
    <Router>
      <ScrollToTop />
      <Routes>
        <Route path="/" element={<Recipes />} />
        <Route path="/login" element={<Login />} />
        <Route path="/chat" element={<Chat />} />
        <Route path="/events" element={<Events />} />
        <Route path="/settings" element={<Settings />} />
      </Routes>
    </Router>
  );
}

export default App;

```

### src/index.tsx

```typescript
import React from 'react';
import ReactDOM from 'react-dom';
import { StrictMode } from 'react';
import { Auth0Provider } from '@auth0/auth0-react';
import { Authenticated, AuthLoading, ConvexReactClient, Unauthenticated } from 'convex/react';
import { ConvexProviderWithAuth0 } from 'convex/react-auth0';
import App from './App';
import Login from './pages/Login';
import reportWebVitals from './reportWebVitals';

const root = document.getElementById('root');

if (!root) {
  throw new Error('Root element not found');
}

const convex = new ConvexReactClient(process.env.REACT_APP_CONVEX_URL!);

ReactDOM.render(
  <StrictMode>
    <Auth0Provider
      domain="dev-6huwnppz7pgz5wml.us.auth0.com"
      clientId="6RMCNgM9Qe303ZOMufvYDQA2kxxVUKke"
      authorizationParams={{
        redirect_uri: window.location.origin,
      }}
      useRefreshTokens={true}
      cacheLocation="localstorage"
    >
      <ConvexProviderWithAuth0 client={convex}>
        <Authenticated>
          <App />
        </Authenticated>
        <Unauthenticated>
          <Login />
        </Unauthenticated>
        <AuthLoading>
          <main>Loading...</main>
        </AuthLoading>
      </ConvexProviderWithAuth0>
    </Auth0Provider>
  </StrictMode>,
  root // Changed this line
);

reportWebVitals();

```

### src/convex/_generated/server.js

```javascript
/* eslint-disable */
/**
 * Generated utilities for implementing server-side Convex query and mutation functions.
 *
 * THIS CODE IS AUTOMATICALLY GENERATED.
 *
 * Generated by convex@1.9.0.
 * To regenerate, run `npx convex dev`.
 * @module
 */

import {
  actionGeneric,
  httpActionGeneric,
  queryGeneric,
  mutationGeneric,
  internalActionGeneric,
  internalMutationGeneric,
  internalQueryGeneric,
} from "convex/server";

/**
 * Define a query in this Convex app's public API.
 *
 * This function will be allowed to read your Convex database and will be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const query = queryGeneric;

/**
 * Define a query that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to read from your Convex database. It will not be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const internalQuery = internalQueryGeneric;

/**
 * Define a mutation in this Convex app's public API.
 *
 * This function will be allowed to modify your Convex database and will be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const mutation = mutationGeneric;

/**
 * Define a mutation that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to modify your Convex database. It will not be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const internalMutation = internalMutationGeneric;

/**
 * Define an action in this Convex app's public API.
 *
 * An action is a function which can execute any JavaScript code, including non-deterministic
 * code and code with side-effects, like calling third-party services.
 * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
 * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
 *
 * @param func - The action. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
 */
export const action = actionGeneric;

/**
 * Define an action that is only accessible from other Convex functions (but not from the client).
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
 */
export const internalAction = internalActionGeneric;

/**
 * Define a Convex HTTP action.
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
 * as its second.
 * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
 */
export const httpAction = httpActionGeneric;

```

### 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';

```

### 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();
});

```

### 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;

```

### src/index.css

```css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

```

### src/useStoreUserEffect.ts

```typescript
import { useAuth0 } from "@auth0/auth0-react";
import { useConvexAuth } from "convex/react";
import { useEffect, useState } from "react";
import { useMutation } from "convex/react";
import { api } from "./convex/_generated/api";
import { Id } from "./convex/_generated/dataModel";

export default function useStoreUserEffect() {
  const { isAuthenticated } = useConvexAuth();
  const { user } = useAuth0();
  // When this state is set we know the server
  // has stored the user.
  const [userId, setUserId] = useState<Id<"users"> | null>(null);
  const storeUser = useMutation(api.users.store);
  // Call the `storeUser` mutation function to store
  // the current user in the `users` table and return the `Id` value.
  useEffect(() => {
    // If the user is not logged in don't do anything
    if (!isAuthenticated) {
      return;
    }
    // Store the user in the database.
    // Recall that `storeUser` gets the user information via the `auth`
    // object on the server. You don't need to pass anything manually here.
    async function createUser() {
      const id = await storeUser();
      setUserId(id);
    }
    createUser();
    return () => setUserId(null);
    // Make sure the effect reruns if the user logs in with
    // a different identity
  }, [isAuthenticated, storeUser, user?.id]);
  return userId;
}

```

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