Skip to content

Recipe generator fix #122

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

Merged
merged 4 commits into from
Mar 14, 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
45 changes: 26 additions & 19 deletions examples/recipegenerator/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,34 @@ def index():

@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
if 'images' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':

files = request.files.getlist('images')

if not files or files[0].filename == '':
return jsonify({'error': 'No selected file'}), 400
if file:
filename = os.path.join(app.config['UPLOAD_FOLDER'], GROCERY_PHOTO_FILE_NAME)
file.save(filename)
try:
# Execute the script to generate the recipe
subprocess.Popen(f"gptscript {SCRIPT_PATH}", shell=True, stdout=subprocess.PIPE, cwd=base_dir).stdout.read()

# Read recipe.md file
recipe_file_path = os.path.join(app.config['UPLOAD_FOLDER'], RECIPE_FILE_NAME)
with open(recipe_file_path, 'r') as recipe_file:
recipe_content = recipe_file.read()

# Return recipe content
return jsonify({'recipe': recipe_content})
except Exception as e:
return jsonify({'error': str(e)}), 500

# Initialize a counter for file naming
file_counter = 1
for file in files:
if file:
# Format the filename as "GroceryX.png"
filename = f"grocery{file_counter}.png"
save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(save_path)
file_counter += 1 # Increment the counter for the next file

try:
# Calling the recipegenerator.gpt script
subprocess.Popen(f"gptscript {SCRIPT_PATH}", shell=True, stdout=subprocess.PIPE).stdout.read()
recipe_file_path = os.path.join(app.config['UPLOAD_FOLDER'], RECIPE_FILE_NAME)
with open(recipe_file_path, 'r') as recipe_file:
recipe_content = recipe_file.read()
# Return the recipe content
return jsonify({'recipe': recipe_content})
except Exception as e:
return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
app.run(debug=False)
5 changes: 3 additions & 2 deletions examples/recipegenerator/recipegenerator.gpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ tools: sys.find, sys.read, sys.write, recipegenerator, tool.gpt

Perform the following steps in order:

1. Give me a list of 5 to 10 ingredients from the picture grocery.png located in the current directory and put those extracted ingredients into a list.
2. Based on these ingredients list, suggest me one recipe that is quick to cook and create a new recipe.md file with the recipe
1. Give me a list of ingredients from the pictures named with grocery in their name located in the current directory and put those extracted ingredients into a list.
2. For each picture analyzed in the previous step, write the ingredients identified into one file name ingredients.md.
3. Based on these ingredients list, suggest me one recipe that is quick to cook and create a new recipe.md file with the recipe


---
Expand Down
111 changes: 68 additions & 43 deletions examples/recipegenerator/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Recipe Generator</title>
<title>RecipAI - Recipe Generator</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/showdown.min.js"></script>
<link rel="stylesheet" href="styles.css">
Expand All @@ -26,7 +26,7 @@
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="#">Recipe Generator</a>
<a class="navbar-brand" href="#">RecipAI - Recipe Generator</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
Expand All @@ -44,56 +44,81 @@
</nav>

<div class="container my-5">
<h1>Recipe Generator</h1>
<div class="col-lg-8 px-0">
<p class="fs-8">Don't know what to do with what's in your shopping cart? Well, click a picture and upload the image to Recipe Generator that will give you interesting ideas of what you can cook from those ingredients! This is built using <a href="https://github.com/gptscript-ai/gptscript" target="_blank">GPTScript</a>.</p>
</div>
<h1>RecipAI - Recipe Generator</h1>
<p class="fs-8">Don't know what to do with what's in your shopping cart? Well, click a picture and upload the image to Recipe Generator that will give you interesting ideas of what you can cook from those ingredients! This is built using <a href="https://github.com/gptscript-ai/gptscript" target="_blank">GPTScript</a>.</p>
</div>

<div class="container my-5">
<div class="mb-3">
<form id="uploadForm">
<form id="uploadForm" enctype="multipart/form-data">
<div class="input-group">
<input type="file" name="file" class="form-control" id="formFile" aria-describedby="inputGroupFileAddon04" aria-label="Upload">
<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04" onclick="uploadFile()">Upload File</button>
</div>
<input type="file" name="images" class="form-control" id="formFile" aria-describedby="inputGroupFileAddon04" aria-label="Upload" multiple>
<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04" onclick="uploadFile()">Upload Files</button>
</div>
</form>
</div>
<div id="loader" class="loader"></div>
<div id="randomMessage" class="mt-3"></div> <!-- Placeholder for random messages -->
<div id="recipeOutput"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Define uploadFile globally
window.uploadFile = function() {
var form = document.getElementById('uploadForm');
var formData = new FormData(form);
var loader = document.getElementById('loader');
var recipeOutput = document.getElementById('recipeOutput');
loader.style.display = 'block'; // Show the loader

fetch('/upload', {
method: 'POST',
body: formData,
})
.then(response => response.json()) // Parse the JSON response
.then(data => {
loader.style.display = 'none'; // Hide the loader
if(data.recipe) {
var converter = new showdown.Converter()
var parsedHtml = converter.makeHtml(data.recipe);
recipeOutput.innerHTML = parsedHtml; // Display the recipe
} else if (data.error) {
recipeOutput.innerHTML = `<p>Error: ${data.error}</p>`;
}
})
.catch(error => {
console.error('Error:', error);
loader.style.display = 'none';
recipeOutput.innerHTML = `<p>Error: ${error}</p>`;
});
};
});
</script>
</div>

<script>
const randomMessages = [
"Hang tight! We're cooking up some suggestions.",
"Did you know? The world's most expensive pizza costs $12,000!",
"Cooking tip: Always taste as you go.",
"A watched pot never boils, but we're fast!",
"Finding recipes... Maybe it's a good day for pasta?",
"Good food takes time, but we'll be quick!",
"Analyzing ingredients... Let's surprise you with something delicious!",
"Cooking is like love. It should be entered into with abandon or not at all."
];

document.addEventListener('DOMContentLoaded', function() {
window.uploadFile = function() {
var form = document.getElementById('uploadForm');
var formData = new FormData(form);
var loader = document.getElementById('loader');
var recipeOutput = document.getElementById('recipeOutput');
loader.style.display = 'block'; // Show the loader

// Display a random message
var messageDiv = document.getElementById('randomMessage');
messageDiv.innerHTML = randomMessages[Math.floor(Math.random() * randomMessages.length)]; // Display initial random message
var messageInterval = setInterval(function() {
messageDiv.innerHTML = randomMessages[Math.floor(Math.random() * randomMessages.length)];
}, 5000); // Change message every 5 seconds


fetch('/upload', {
method: 'POST',
body: formData,
})
.then(response => response.json()) // Parse the JSON response
.then(data => {
clearInterval(messageInterval); // Stop changing messages
loader.style.display = 'none'; // Hide the loader
if(data.recipe) {
var converter = new showdown.Converter();
var html = converter.makeHtml(data.recipe);
recipeOutput.innerHTML = html; // Display the converted HTML
messageDiv.innerHTML = ''; // Clear message
} else if (data.error) {
recipeOutput.innerHTML = `<p>Error: ${data.error}</p>`;
messageDiv.innerHTML = ''; // Clear message
}

})
.catch(error => {
console.error('Error:', error);
loader.style.display = 'none';
recipeOutput.innerHTML = `<p>Error: ${error}</p>`;
clearInterval(messageInterval); // Ensure interval is cleared on error
messageDiv.innerHTML = ''; // Clear message
});
};
});
</script>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
Expand Down