DEV Community

Cover image for How to Create a Recipe Generator with NextJS, LangChain, and OpenAI
Daniel Musembi
Daniel Musembi

Posted on

How to Create a Recipe Generator with NextJS, LangChain, and OpenAI

Hey there ๐Ÿ‘‹ , I hope you're doing great. This is just a quick guide on how you can build amazing applications using AI.

Inspiration for me to build a recipe generator comes from wanting to solve the mental problem of deciding what to eat. you know they say making too many small decisions causes you to suffer fromdecisions fatigue - which is basically mental exhaustion resulting from the sheer number of decisions a person must make daily, leading to difficulty makingโ€”or making goodโ€”decisions. Now just imagine an application in which you just need to key in the ingredients, click the generate button then boom ๐Ÿ’ฅ there you have generated the recipe. That is what we are going to build step by step. Check below what we will be building ๐Ÿ‘‡๐Ÿ‘‡

Image description

Without any further ado let's dive in

Step1. Create new project

First, ensure you have Node.js installed, then run the following command on the terminal to initialise a Nextjs project.

npx create-next-app recipe-generator
cd recipe-generator
Enter fullscreen mode Exit fullscreen mode

Step2. Install required packages

Run the following to install packages we will be using

npm install langchain
npm install openai dotenv
Enter fullscreen mode Exit fullscreen mode

Let's get to understand the two,

LangChain LangChain is a tool that helps create applications using large language models (LLMs). It provides a framework to connect these models with various data sources, such as APIs and databases, making it easier to build more advanced AI applications like chatbots, content generators, and data analyzers. Essentially, LangChain streamlines the process of integrating and using AI models in different projects.

OpenAI is the organization behind some of the most advanced AI models, like GPT, which can generate text, answer questions, and perform a variety of other tasks. The OpenAI API allows developers to access these powerful models and use them in their own applications. While OpenAI provides the AI models, LangChain acts as the framework that can connect these models with other tools and data sources, enabling the creation of complex AI-driven applications.

Together, OpenAI and LangChain can be used to build sophisticated AI systems. OpenAI offers the intelligence, and LangChain provides the tools to integrate that intelligence into useful, real-world applications.

Step3. Configure Environment variables

Create a .env.local file in the root directory. Go to openai and create a new project, click on the dashboard and select API keys from the left sidebar to copy your openai-api-key.

Image description

Insert your api key in the .env.local file as shown below

OPENAI_API_KEY=your opeai-api-key
Enter fullscreen mode Exit fullscreen mode

Step4. Setup the API connection

In the app directory create langchain.ts file and in it insert the following code

// aap/langchain.ts

import { OpenAI } from '@langchain/openai'
import  dotenv  from 'dotenv';

dotenv.config();

const model = new OpenAI({
  openAIApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY,
  temperature: 0.7, // Adjust for creativity vs. accuracy
});

export default model;
Enter fullscreen mode Exit fullscreen mode

Here we set up an OpenAI model using the LangChain library, configuring it with an API key and creativity level from environment variables. We then export this model so it can be used throughout the web application.

Step5. Creating recipe generator logic

In the app directory create a new file recipeGenerator.ts and copy and paste the following code into it.

// app/recipeGenerator.ts
import model from './langchain';

export async function generateRecipe(ingredients: string[]): Promise<string> {
  const prompt = `Generate a recipe using the following ingredients: ${ingredients.join(', ')}. Please include the steps for preparation.`;
  const response = await model.call(prompt);
  return response;
}
Enter fullscreen mode Exit fullscreen mode

Here we are defining a function generateRecipe that takes a list of ingredients as input and uses the OpenAI model (imported from langchain.ts) to create a recipe. The function constructs a prompt with the ingredients, sends it to the model to generate a recipe, and then returns the recipe text.

Step6. Create frontend to use the API

Insert the following code into the page.tsx file.

// app/page.tsx

"use client"; // Ensure this is a client component

import { useState } from 'react';
import { generateRecipe } from './recipeGenerator'; // Adjust path if needed

const Home = () => {
  const [ingredients, setIngredients] = useState<string[]>([]);
  const [recipe, setRecipe] = useState<string>('');
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setIsLoading(true);
    setError(null);

    try {
      const newRecipe = await generateRecipe(ingredients);
      setRecipe(newRecipe);
    } catch (err) {
      console.error("Error generating recipe:", err);
      setError('Failed to generate recipe. Please try again.');
    } finally {
      setIsLoading(false);
    }
  };

  const handleIngredientsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newIngredients = e.target.value
      .split(',')
      .map(i => i.trim())
      .filter(i => i.length > 0);

    setIngredients(newIngredients);
  };

  return (
    <div style={{ padding: '20px', border: '2px solid blue' }}> {/* Debugging styles */}
      <h1>AI Recipe Generator</h1>
      <form onSubmit={handleSubmit}>
        <input 
          type="text" 
          value={ingredients.join(', ')} 
          onChange={handleIngredientsChange}
          placeholder="Enter ingredients separated by commas"
        />
        <button type="submit" disabled={isLoading}>
          {isLoading ? 'Generating...' : 'Generate Recipe'}
        </button>
      </form>
      {error && <p style={{ color: 'red' }}>{error}</p>}
      {recipe && (
        <div>
          <h2>Generated Recipe:</h2>
          <p>{recipe}</p>
        </div>
      )}
    </div>
  );
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

Here we are creating a React component for an AI recipe generator. Users input ingredients into a text field, which is then processed to generate a recipe using the generateRecipe function. The component handles form submission, displays loading states, and shows any errors or the generated recipe.

Step7. Styling our component

To style our application, insert the following CSS code in the global.css file

@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
  --foreground-rgb: 50, 50, 50; /* Slightly lighter dark grey for text */
  --background-start-rgb: 255, 248, 240; /* Warm beige for start */
  --background-end-rgb: 255, 255, 255; /* Soft white for end */
  --highlight-color: 255, 140, 0; /* Orange for highlights and accents */
}

@media (prefers-color-scheme: dark) {
  :root {
    --foreground-rgb: 240, 240, 240; /* Light grey text for dark mode */
    --background-start-rgb: 34, 34, 34; /* Dark grey for start */
    --background-end-rgb: 0, 0, 0; /* Black for end */
    --highlight-color: 255, 165, 0; /* Lighter orange for highlights in dark mode */
  }
}

body {
  color: rgb(var(--foreground-rgb));
  background: linear-gradient(
      to bottom,
      rgb(var(--background-start-rgb)),
      rgb(var(--background-end-rgb))
    );
  font-family: 'Poppins', sans-serif;
  line-height: 1.7;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}

h1, h2, h3, h4, h5, h6 {
  color: rgb(var(--highlight-color)); /* Warm orange color for headings */
  font-family: 'Merriweather', serif; /* Add a serif font for headings */
  text-align: center;
  margin-bottom: 20px;
}

.container {
  width: 90%;
  max-width: 600px;
  box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
  padding: 20px;
  border-radius: 8px;
  background-color: #fff;
  margin-bottom: 20px;
}

button {
  background-color: rgb(var(--highlight-color));
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 12px 24px;
  font-size: 18px;
  font-family: 'Poppins', sans-serif;
  cursor: pointer;
  box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
  transition: background-color 0.3s ease, transform 0.3s ease;
  width: 100%;
  margin-top: 10px;
}

button:hover {
  background-color: #e68a00; /* Darker orange on hover */
  transform: translateY(-2px); /* Slight lift effect */
}

input {
  border: 2px solid rgb(var(--highlight-color));
  border-radius: 8px;
  padding: 12px;
  font-size: 16px;
  margin-bottom: 12px;
  width: 100%;
  box-sizing: border-box;
  font-family: 'Poppins', sans-serif;
}

input:focus {
  outline: none;
  border-color: #e68a00; /* Darker orange on focus */
  box-shadow: 0 0 5px rgba(255, 140, 0, 0.5);
}

/* Remove debugging styles */
* {
  border: none;
}
Enter fullscreen mode Exit fullscreen mode

Finally, we've set up a layout.tsx file to define the overall structure of our AI Recipe Generator application. This file applies global styles, sets metadata (like the page title and description), and organizes the main layout by wrapping all content (children) in a consistent header, main section, and footer. The debugging border helps visualize the main content area during development.

// app/layout.tsx
import './globals.css';

export const metadata = {
  title: 'AI Recipe Generator',
  description: 'Generate recipes using AI',
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <header>
          {/* Header content */}
        </header>
        <main>
          <div style={{ border: '1px solid red' }}> {/* Added for debugging */}
            {children}
          </div>
        </main>
        <footer>
          {/* Footer content */}
        </footer>
      </body>
    </html>
  );
}

Enter fullscreen mode Exit fullscreen mode

Run the application and see it in action

npm run dev
Enter fullscreen mode Exit fullscreen mode

Image description

That's it guys, if you liked this tutorial kindly share it with others and make sure you follow me for much more ๐Ÿฅ‚. let me also know if you need the source code.

Follow me on X

Follow me on LinkedIn

Top comments (0)