Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added loading for edit recipe and changed prompt for edit recipe #102

Merged
merged 2 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 95 additions & 49 deletions components/EditRecipeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
'use client';

import { useState } from 'react';
import { useState, useCallback } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Checkbox } from '@/components/ui/checkbox';
import { X, Plus } from 'lucide-react';
import { X, Plus, Loader2 } from 'lucide-react';
import OpenAI from 'openai';
import { useCallback } from 'react';

const openaiKey = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
let openai: OpenAI;
if (openaiKey) {
openai = new OpenAI({ apiKey: openaiKey, dangerouslyAllowBrowser: true });
} else {
console.warn('OpenAI API key not found. Some features may not work.');
}
let openai: OpenAI;
if (openaiKey) {
openai = new OpenAI({ apiKey: openaiKey, dangerouslyAllowBrowser: true });
} else {
console.warn('OpenAI API key not found. Some features may not work.');
}

interface EditRecipeCardProps {
recipe: any;
Expand All @@ -33,19 +31,35 @@ export default function EditRecipeCard({
...recipe,
instructions: recipe.instructions || '',
});
const [isUpdating, setIsUpdating] = useState(false);
const [isSaving, setIsSaving] = useState(false);

// Initialize ingredients with 'selected' property
const [ingredients, setIngredients] = useState(
recipe.extendedIngredients.map((ing: any) => ({
...ing,
selected: ing.selected !== undefined ? ing.selected : true,
}))
);
// Remove duplicates and initialize ingredients with 'selected' property and unique id
const uniqueIngredients = () => {
const seen = new Set();
const result = [];
for (const ing of recipe.extendedIngredients) {
const original = ing.original.trim().toLowerCase();
if (!seen.has(original)) {
seen.add(original);
result.push({
...ing,
selected: ing.selected !== undefined ? ing.selected : true,
id: Date.now() + Math.random(), // unique id for this ingredient
});
}
}
return result;
};

const [ingredients, setIngredients] = useState(uniqueIngredients());

const handleIngredientToggle = (index: number) => {
const updatedIngredients = [...ingredients];
updatedIngredients[index].selected = !updatedIngredients[index].selected;
setIngredients(updatedIngredients);
setIngredients((prevIngredients: any) => {
const updatedIngredients = [...prevIngredients];
updatedIngredients[index].selected = !updatedIngredients[index].selected;
return updatedIngredients;
});
};

const handleIngredientEdit = (index: number, newValue: string) => {
Expand All @@ -57,9 +71,9 @@ export default function EditRecipeCard({
};

const handleAddIngredient = () => {
setIngredients([
...ingredients,
{ id: Date.now(), original: '', selected: true },
setIngredients((prevIngredients: any) => [
...prevIngredients,
{ id: Date.now() + Math.random(), original: '', selected: true },
]);
};

Expand All @@ -72,31 +86,29 @@ export default function EditRecipeCard({
};

const handleUpdateRecipe = async () => {
// Your existing handleUpdateRecipe function
const selectedIngredients = ingredients.filter(
(ingredient: any) => ingredient.selected
);
setIsUpdating(true);
const selectedIngredients = ingredients.filter((ingredient: any) => ingredient.selected);
console.log('Allowed ingredients:', selectedIngredients.map((ing: any) => ing.original));

try {
const response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content:
'You are a culinary expert tasked with updating recipes based on ingredient changes.',
content: 'You are a culinary expert tasked with updating recipes based on a strict set of allowed ingredients.'
},
{
role: 'user',
content: `Here is the original recipe: ${editedRecipe.instructions}.
Here are the only ingredients we have: ${selectedIngredients
.map((ing: any) => ing.original)
.join(', ')}.
Edit the recipe as little as possible with these new ingredients. Make sure not to include any ingredient not in the list.
Strictly include the ingredient amount values and only use the new ingredients in the instructions.
Strictly just write out the instructions very descriptively, nothing else.`,
},
],
content: `
IGNORE PREVIOUS HISTORY. DO NOT USE INGREDIENTS OUTSIDE OF THE FOLLOWING LIST.
Update the recipe using only these ingredients: ${selectedIngredients.map((ing: any) => ing.original).join(', ')}.
- Use all allowed ingredients and maintain their amounts.
- Exclude or replace any disallowed ingredients.
- Provide concise step-by-step instructions only, without commentary or mentioning changes.
Original recipe: ${editedRecipe.instructions}`
}
],
temperature: 0.7,
max_tokens: 500,
});
Expand All @@ -111,6 +123,8 @@ export default function EditRecipeCard({
}));
} catch (error) {
console.error('Error updating recipe:', error);
} finally {
setIsUpdating(false);
}
};

Expand All @@ -123,6 +137,7 @@ export default function EditRecipeCard({
);

const handleSave = async () => {
setIsSaving(true);
const { _id, ...recipeToUpdate } = editedRecipe; // Exclude _id
const updatedRecipe = {
...recipeToUpdate,
Expand All @@ -141,15 +156,15 @@ export default function EditRecipeCard({
const data = await response.json();

if (response.ok) {
// Update successful
console.log('Recipe updated successfully:', data);
onSave(updatedRecipe); // Optionally update parent state or close modal
onSave(updatedRecipe);
} else {
// Handle error
console.error('Failed to update recipe:', data.error);
}
} catch (error) {
console.error('Error updating recipe:', error);
} finally {
setIsSaving(false);
}
};

Expand All @@ -162,12 +177,23 @@ export default function EditRecipeCard({
<div className="w-1/2 pr-4">
{/* Left side: The recipe details */}
<h3 className="text-xl font-semibold mb-2">Recipe</h3>
<div className="border-2 border-indigo-300 rounded-lg p-4 bg-indigo-50 shadow-md">
<div className="border-2 border-indigo-300 rounded-lg p-4 bg-indigo-50 shadow-md relative">
{isUpdating && (
<div className="absolute inset-0 bg-white/80 backdrop-blur-sm flex items-center justify-center rounded-lg">
<div className="text-center">
<Loader2 className="h-8 w-8 animate-spin text-indigo-600 mx-auto mb-2" />
<p className="text-indigo-600 font-medium">Updating Recipe...</p>
</div>
</div>
)}
{/* Display the updated ingredients list */}
<h4 className="font-medium text-lg mb-2">Ingredients:</h4>
<ul className="list-disc list-inside mb-4">
{ingredients.map((ingredient: any, index: number) => (
<li key={ingredient.id} className={`${!ingredient.selected ? 'line-through text-gray-400' : ''}`}>
{ingredients.map((ingredient: any) => (
<li
key={ingredient.id}
className={`${!ingredient.selected ? 'line-through text-gray-400' : ''}`}
>
{ingredient.original}
</li>
))}
Expand All @@ -177,7 +203,7 @@ export default function EditRecipeCard({
<div className="text-base leading-relaxed">
{editedRecipe.instructions
.split('\n')
.map((line: any, index: number) => (
.map((line: string, index: number) => (
<div key={index}>{line}</div>
))}
</div>
Expand Down Expand Up @@ -210,17 +236,37 @@ export default function EditRecipeCard({
<Button onClick={handleAddIngredient} className="mt-2">
<Plus className="h-4 w-4 mr-2" /> Add Ingredient
</Button>
<Button onClick={handleUpdateRecipe} className="mt-4 w-full">
Update Recipe
<Button
onClick={handleUpdateRecipe}
className="mt-4 w-full"
disabled={isUpdating}
>
{isUpdating ? (
<>
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
Updating Recipe...
</>
) : (
'Update Recipe'
)}
</Button>
</div>
</CardContent>
<div className="fixed bottom-4 right-4">
<Button onClick={onCancel} variant="outline" className="mr-2">
Cancel
</Button>
<Button onClick={handleSave}>Save Changes</Button>
<Button onClick={handleSave} disabled={isSaving}>
{isSaving ? (
<>
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
Saving...
</>
) : (
'Save Changes'
)}
</Button>
</div>
</Card>
);
}
}
108 changes: 0 additions & 108 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading