Create an AI-Powered Side Project in Just One Day
Side projects are the key to building your online presence and enhancing your coding skills.
Are you ready to dive in?
I created a Recipe Generator app within a few days using Claude AI. Here’s how I did it.
Getting Started
First, I initiated a new Next.js project. I chose Tailwind CSS and the new app router to keep things streamlined.
npx create-next-app@latest
Layout
I used Claude AI to generate the layout of my app.
Here was my initial prompt:
Generate a webpage in react using tailwindcss and shadcn/ui.
Header with logo and app name [ Recipe Creator ] on the right side login button.
Main content with
1. Select ingredients dropdown.
2. Other inputs should contain the user's personal dietary restrictions, Flavour, Allergies and ingredient exclusions, Preferred cuisines, Texture Preferences, Available cooking time, Nutritional goals, Cooking Method Preferences
Finally with submit button
I then used the generated code and adjusted my prompt and respective code based on my requirements. It’s a great way to save time and get a solid starting point.
Creating the Recipe Generator API
Now that the UI was ready, I needed an API to generate recipes based on the input. Claude Haiku was the perfect choice for this, being both affordable and capable.
I signed up for Claude API access here, where they offer $5 in API credit. It took a few weeks for my application to be processed.
The console dashboard is quite handy for generating prompts. I used it to create prompts for recipe creation and stored those prompts as strings in my config.
export const RECIPE_PROMPT = `
You are a sophisticated cooking assistant AI designed to help users generate comprehensive recipes. Your task is to create a detailed recipe based on the user's input, which may include ingredients they have, recipe name, servings, dietary restrictions, flavor preferences, allergies, ingredient exclusions, preferred cuisines, texture preferences, available cooking time, nutritional goals, and cooking method preferences.
Begin by carefully analyzing the following user input:
<user_input>
{{USER_INPUT}}
</user_input>
Process the user input to identify key information such as:
1. Available ingredients or recipe name
2. Number of servings (if specified)
3. Dietary restrictions or preferences
4. Flavor preferences
5. Allergies or ingredient exclusions
6. Preferred cuisines
7. Texture preferences
8. Available cooking time
9. Nutritional goals
10. Cooking method preferences
If any of this information is missing, make reasonable assumptions based on the provided input.
Next, create a comprehensive recipe that addresses the user's requirements. Your recipe should include the following components:
1. Recipe Name: Create an appealing name for the dish.
2. Ingredients List: Provide a detailed list of ingredients with precise measurements. Ensure that the ingredients align with the user's preferences, restrictions, and available items.
3. Create detailed cooking instructions, including preparation and cooking times. Include a timer for each major step in the cooking process.
4. Nutrition Information: Provide an estimated breakdown of key nutritional values per serving, such as calories, protein, carbohydrates, fat, fiber, and any other relevant nutrients based on the user's goals.
5. Interesting Facts: Include 1-2 interesting facts about the dish, its ingredients, or its cultural significance.
6. Similar Dish Suggestions: Recommend 2-3 similar dishes that the user might enjoy based on their preferences.
Format your output in JSON string as follows without any additional text:
{
"recipe_detail": {
"name": "[Recipe Name]",
"ingredients": "[List of ingredients with measurements as array of objects]",
"instructions": "[{"step": number, "instruction": 'instruction', timer: 'number and mins/hrs information'}]",
"nutrition": "{"calories: "Nutrition Value Nutrition Unit" like wise for protein, carbohydrates, fat, fiber}",
"facts": "[1-2 interesting facts]",
"similar_dishes": "[2-3 similar dish suggestions]"
}
}
Special considerations:
1. If the user has specified dietary restrictions (e.g., vegetarian, vegan, gluten-free), ensure that all ingredients and cooking methods comply with these restrictions.
2. If the user has mentioned allergies or ingredient exclusions, double-check that none of these items are included in the recipe.
3. Adapt the recipe complexity and cooking time to match the user's available time and cooking method preferences.
4. If the user has specified nutritional goals, try to align the recipe with these objectives as much as possible.
5. Be creative and flexible in your approach, especially if the user has limited ingredients or specific constraints.
`
Next, I created an API under app/api/generate-recipe
.
export async function POST(request: Request) {
const body = await request.json();
const { userInput, type, ingredientToReplace, alternativeIngredient = 'Suggest something else' } = body;
if (!userInput) {
return NextResponse.json({ message: 'User input is required' }, { status: 400 });
}
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
console.error('Anthropic API key is not set');
return NextResponse.json({ message: 'Server configuration error' }, { status: 500 });
}
const anthropic = new Anthropic({
apiKey: apiKey,
});
let fullPrompt;
if (type === TYPES.GENERATE_RECIPE) {
fullPrompt = RECIPE_PROMPT.replace('{{USER_INPUT}}', JSON.stringify(userInput));
} else if (type === TYPES.RECIPE_SUGGESTION) {
fullPrompt = RECIPE_SUGGESTION_PROMPT.replace('{{USER_INPUT}}', JSON.stringify(userInput));
} else if (type === TYPES.REGENERATE_WITH_ALTERNATE_INGREDIENTS) {
fullPrompt = REGENERATE_WITH_ALTERNATE_INGREDIENTS
.replace('{{RECIPE_JSON}}', JSON.stringify(userInput))
.replace('{{INGREDIENT_TO_REPLACE}}', JSON.stringify(ingredientToReplace))
.replace('{{ALTERNATIVE_INGREDIENT}}', JSON.stringify(alternativeIngredient));
} else {
return NextResponse.json({ message: 'Invalid type specified' }, { status: 400 });
}
try {
const response = await anthropic.messages.create({
model: 'claude-3-haiku-20240307',
max_tokens: 1500,
temperature: 0.7,
system: 'You are a sophisticated cooking assistant AI.',
messages: [
{ role: 'user', content: fullPrompt }
]
});
const recipeText = response.content[0].type === 'text'
? response.content[0].text
: 'Unable to generate recipe text';
return NextResponse.json({ recipe: recipeText, remaining });
} catch (error) {
console.error('Error calling Claude API:', error);
return NextResponse.json({ message: 'Error generating recipe' }, { status: 500 });
}
}
Once done, the UI would receive recipe suggestions as an array, and if it's a detailed recipe, in a JSON object.
Implementing Rate Limiting
What if we receive too many requests? Our API credits would be fully consumed, right? To prevent this, I added rate limiting to the API requests, allowing only five requests per guest user. I implemented rate limiting based on the IP address.
Here’s a snippet of the code for rate limiting:
const ipStore: Map<string, IPData> = new Map();
export function rateLimit(ip: string): boolean {
const now: number = Date.now();
const ipData: IPData = ipStore.get(ip) || { count: 0, resetTime: now + WINDOW };
if (now > ipData.resetTime) {
ipData.count = 1;
ipData.resetTime = now + WINDOW;
} else if (ipData.count < LIMIT) {
ipData.count++;
} else {
return false; // Rate limit exceeded
}
ipStore.set(ip, ipData);
return true; // Request allowed
}
Since this is a demo project, I didn’t add Redis or a database. Every time we restart the app, the remaining count is cleared.
Conclusion
Giving life to your ideas is very easy nowadays. Leverage AI tools, use any frameworks, and start building today.
Thanks for reading!
Subscribe to my newsletter
Read articles from Ram directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ram
Ram
Full stack developer (React.js & Node.js) with a focus on creating digital experiences that are simple, stunning, and responsive. Even though I have been creating web applications for over 6 years, I still love it as if it was something new. I am also aspiring to become a web artist, continually pushing the boundaries of design and functionality.