recipeGen v1

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-28 19:24:03 -05:00
parent 4831cc7255
commit 2cbc63efd3
4 changed files with 1064 additions and 16 deletions

3
.gitignore vendored
View File

@@ -60,3 +60,6 @@ fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
node_modules/
.env

View File

@@ -181,15 +181,18 @@
</div>
</div>
<button class="generate-btn" id="gen-btn" onclick="generate()">Generate my recipe</button>
<button class="generate-btn" id="gen-btn">Generate my recipe</button>
<div id="error-area"></div>
<div id="recipe-area"></div>
</div>
<script>
<script type="module">
const ingredients = [];
const ingWrapper = document.getElementById('ing-wrapper');
const ingInput = document.getElementById('ing-input');
const genBtn = document.getElementById('gen-btn');
genBtn.addEventListener('click', generate);
ingWrapper.addEventListener('click', () => ingInput.focus());
ingInput.addEventListener('keydown', e => {
@@ -268,24 +271,30 @@
CRITICAL: Instructions must be specific — never vague. Include exact temperatures, times, visual cues, sounds, smells, and textures. Example: instead of "cook the onions", write "cook the onions in the butter over medium heat, stirring occasionally, for 810 minutes until they turn translucent and just begin to turn golden at the edges."
Respond with ONLY a valid JSON object — no markdown fences, no backticks, no explanation, nothing before or after the JSON. Use this exact structure:
Respond with ONLY a valid JSON object. Use this exact structure:
{"title":"string","description":"string","servings":2,"prepTime":"string","cookTime":"string","ingredients":[{"amount":"string","unit":"string","name":"string"}],"steps":[{"title":"string","instruction":"string"}],"notes":"string or null"}
Rules: use provided ingredients as the base, add pantry staples as needed, 510 steps, each instruction 13 richly detailed sentences, respect all dietary restrictions strictly.`;
try {
const resp = await fetch('https://api.anthropic.com/v1/messages', {
// Vite will inject this automatically from the .env file
const API_KEY = import.meta.env.VITE_GEMINI_API_KEY;
const resp = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${API_KEY}`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'anthropic-version': '2023-06-01',
'anthropic-dangerous-direct-browser-access': 'true'
'content-type': 'application/json'
},
body: JSON.stringify({
model: 'claude-sonnet-4-20250514',
max_tokens: 1800,
system: systemPrompt,
messages: [{ role: 'user', content: userPrompt }]
systemInstruction: {
parts: [{ text: systemPrompt }]
},
contents: [{
parts: [{ text: userPrompt }]
}],
generationConfig: {
responseMimeType: "application/json"
}
})
});
@@ -295,11 +304,8 @@ Rules: use provided ingredients as the base, add pantry staples as needed, 51
throw new Error(data.error?.message || `API error ${resp.status}`);
}
const raw = (data.content || []).map(b => b.text || '').join('').trim();
const jsonStart = raw.indexOf('{');
const jsonEnd = raw.lastIndexOf('}');
if (jsonStart === -1 || jsonEnd === -1) throw new Error('No JSON found in response');
const recipe = JSON.parse(raw.slice(jsonStart, jsonEnd + 1));
const raw = data.candidates[0].content.parts[0].text;
const recipe = JSON.parse(raw);
renderRecipe(recipe);
} catch (err) {

1026
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

13
package.json Normal file
View File

@@ -0,0 +1,13 @@
{
"name": "recipe-generator",
"version": "1.0.0",
"description": "Recipe generator using Gemini",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.0.0"
}
}