Skip to content

Commit c16eca7

Browse files
authored
Recipe generator fix (#122)
* Add Recipe Generate sample application * Fixed comments & updated recipegenerator.gpt * Add support for multiple images
1 parent 49ffc01 commit c16eca7

File tree

3 files changed

+97
-64
lines changed

3 files changed

+97
-64
lines changed

examples/recipegenerator/app.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,34 @@ def index():
1818

1919
@app.route('/upload', methods=['POST'])
2020
def upload_file():
21-
if 'file' not in request.files:
21+
if 'images' not in request.files:
2222
return jsonify({'error': 'No file part'}), 400
23-
file = request.files['file']
24-
if file.filename == '':
23+
24+
files = request.files.getlist('images')
25+
26+
if not files or files[0].filename == '':
2527
return jsonify({'error': 'No selected file'}), 400
26-
if file:
27-
filename = os.path.join(app.config['UPLOAD_FOLDER'], GROCERY_PHOTO_FILE_NAME)
28-
file.save(filename)
29-
try:
30-
# Execute the script to generate the recipe
31-
subprocess.Popen(f"gptscript {SCRIPT_PATH}", shell=True, stdout=subprocess.PIPE, cwd=base_dir).stdout.read()
32-
33-
# Read recipe.md file
34-
recipe_file_path = os.path.join(app.config['UPLOAD_FOLDER'], RECIPE_FILE_NAME)
35-
with open(recipe_file_path, 'r') as recipe_file:
36-
recipe_content = recipe_file.read()
37-
38-
# Return recipe content
39-
return jsonify({'recipe': recipe_content})
40-
except Exception as e:
41-
return jsonify({'error': str(e)}), 500
28+
29+
# Initialize a counter for file naming
30+
file_counter = 1
31+
for file in files:
32+
if file:
33+
# Format the filename as "GroceryX.png"
34+
filename = f"grocery{file_counter}.png"
35+
save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
36+
file.save(save_path)
37+
file_counter += 1 # Increment the counter for the next file
38+
39+
try:
40+
# Calling the recipegenerator.gpt script
41+
subprocess.Popen(f"gptscript {SCRIPT_PATH}", shell=True, stdout=subprocess.PIPE).stdout.read()
42+
recipe_file_path = os.path.join(app.config['UPLOAD_FOLDER'], RECIPE_FILE_NAME)
43+
with open(recipe_file_path, 'r') as recipe_file:
44+
recipe_content = recipe_file.read()
45+
# Return the recipe content
46+
return jsonify({'recipe': recipe_content})
47+
except Exception as e:
48+
return jsonify({'error': str(e)}), 500
4249

4350
if __name__ == '__main__':
4451
app.run(debug=False)

examples/recipegenerator/recipegenerator.gpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ tools: sys.find, sys.read, sys.write, recipegenerator, tool.gpt
22

33
Perform the following steps in order:
44

5-
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.
6-
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
5+
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.
6+
2. For each picture analyzed in the previous step, write the ingredients identified into one file name ingredients.md.
7+
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
78

89

910
---

examples/recipegenerator/templates/index.html

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
6-
<title>Recipe Generator</title>
6+
<title>RecipAI - Recipe Generator</title>
77
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
88
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/showdown.min.js"></script>
99
<link rel="stylesheet" href="styles.css">
@@ -26,7 +26,7 @@
2626
<body>
2727
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
2828
<div class="container">
29-
<a class="navbar-brand" href="#">Recipe Generator</a>
29+
<a class="navbar-brand" href="#">RecipAI - Recipe Generator</a>
3030
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
3131
<span class="navbar-toggler-icon"></span>
3232
</button>
@@ -44,56 +44,81 @@
4444
</nav>
4545

4646
<div class="container my-5">
47-
<h1>Recipe Generator</h1>
48-
<div class="col-lg-8 px-0">
49-
<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>
50-
</div>
47+
<h1>RecipAI - Recipe Generator</h1>
48+
<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>
5149
</div>
5250

5351
<div class="container my-5">
5452
<div class="mb-3">
55-
<form id="uploadForm">
53+
<form id="uploadForm" enctype="multipart/form-data">
5654
<div class="input-group">
57-
<input type="file" name="file" class="form-control" id="formFile" aria-describedby="inputGroupFileAddon04" aria-label="Upload">
58-
<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04" onclick="uploadFile()">Upload File</button>
59-
</div>
55+
<input type="file" name="images" class="form-control" id="formFile" aria-describedby="inputGroupFileAddon04" aria-label="Upload" multiple>
56+
<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04" onclick="uploadFile()">Upload Files</button>
57+
</div>
6058
</form>
6159
</div>
6260
<div id="loader" class="loader"></div>
61+
<div id="randomMessage" class="mt-3"></div> <!-- Placeholder for random messages -->
6362
<div id="recipeOutput"></div>
64-
<script>
65-
document.addEventListener('DOMContentLoaded', function() {
66-
// Define uploadFile globally
67-
window.uploadFile = function() {
68-
var form = document.getElementById('uploadForm');
69-
var formData = new FormData(form);
70-
var loader = document.getElementById('loader');
71-
var recipeOutput = document.getElementById('recipeOutput');
72-
loader.style.display = 'block'; // Show the loader
73-
74-
fetch('/upload', {
75-
method: 'POST',
76-
body: formData,
77-
})
78-
.then(response => response.json()) // Parse the JSON response
79-
.then(data => {
80-
loader.style.display = 'none'; // Hide the loader
81-
if(data.recipe) {
82-
var converter = new showdown.Converter()
83-
var parsedHtml = converter.makeHtml(data.recipe);
84-
recipeOutput.innerHTML = parsedHtml; // Display the recipe
85-
} else if (data.error) {
86-
recipeOutput.innerHTML = `<p>Error: ${data.error}</p>`;
87-
}
88-
})
89-
.catch(error => {
90-
console.error('Error:', error);
91-
loader.style.display = 'none';
92-
recipeOutput.innerHTML = `<p>Error: ${error}</p>`;
93-
});
94-
};
95-
});
96-
</script>
63+
</div>
64+
65+
<script>
66+
const randomMessages = [
67+
"Hang tight! We're cooking up some suggestions.",
68+
"Did you know? The world's most expensive pizza costs $12,000!",
69+
"Cooking tip: Always taste as you go.",
70+
"A watched pot never boils, but we're fast!",
71+
"Finding recipes... Maybe it's a good day for pasta?",
72+
"Good food takes time, but we'll be quick!",
73+
"Analyzing ingredients... Let's surprise you with something delicious!",
74+
"Cooking is like love. It should be entered into with abandon or not at all."
75+
];
76+
77+
document.addEventListener('DOMContentLoaded', function() {
78+
window.uploadFile = function() {
79+
var form = document.getElementById('uploadForm');
80+
var formData = new FormData(form);
81+
var loader = document.getElementById('loader');
82+
var recipeOutput = document.getElementById('recipeOutput');
83+
loader.style.display = 'block'; // Show the loader
84+
85+
// Display a random message
86+
var messageDiv = document.getElementById('randomMessage');
87+
messageDiv.innerHTML = randomMessages[Math.floor(Math.random() * randomMessages.length)]; // Display initial random message
88+
var messageInterval = setInterval(function() {
89+
messageDiv.innerHTML = randomMessages[Math.floor(Math.random() * randomMessages.length)];
90+
}, 5000); // Change message every 5 seconds
91+
92+
93+
fetch('/upload', {
94+
method: 'POST',
95+
body: formData,
96+
})
97+
.then(response => response.json()) // Parse the JSON response
98+
.then(data => {
99+
clearInterval(messageInterval); // Stop changing messages
100+
loader.style.display = 'none'; // Hide the loader
101+
if(data.recipe) {
102+
var converter = new showdown.Converter();
103+
var html = converter.makeHtml(data.recipe);
104+
recipeOutput.innerHTML = html; // Display the converted HTML
105+
messageDiv.innerHTML = ''; // Clear message
106+
} else if (data.error) {
107+
recipeOutput.innerHTML = `<p>Error: ${data.error}</p>`;
108+
messageDiv.innerHTML = ''; // Clear message
109+
}
110+
111+
})
112+
.catch(error => {
113+
console.error('Error:', error);
114+
loader.style.display = 'none';
115+
recipeOutput.innerHTML = `<p>Error: ${error}</p>`;
116+
clearInterval(messageInterval); // Ensure interval is cleared on error
117+
messageDiv.innerHTML = ''; // Clear message
118+
});
119+
};
120+
});
121+
</script>
97122
</div>
98123

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

0 commit comments

Comments
 (0)