This commit is contained in:
Ionel Andrei Cataon
2026-02-18 16:10:54 +02:00
parent 7a3190ac69
commit 1beeb14203

View File

@@ -3,176 +3,183 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sistem Avansat Nutriție AI</title> <title>NutriAI Pro - Sistem Expert Groq</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style> <style>
:root { --primary: #27ae60; --accent: #3498db; --dark: #1e272e; } :root { --primary: #27ae60; --dark: #1e272e; --accent: #3498db; }
body { background: #f1f2f6; font-family: 'Segoe UI', sans-serif; } body { background: #f4f7f6; font-family: 'Inter', sans-serif; overflow-x: hidden; }
.config-panel { background: var(--dark); color: white; min-height: 100vh; padding: 25px; border-radius: 0 30px 30px 0; } .sidebar { background: var(--dark); color: white; min-height: 100vh; padding: 25px; box-shadow: 4px 0 15px rgba(0,0,0,0.1); }
.chat-container { height: 400px; overflow-y: auto; background: #fff; border-radius: 15px; padding: 20px; border: 1px solid #ddd; margin-bottom: 15px; } .chat-container { height: 500px; overflow-y: auto; background: white; border-radius: 20px; padding: 20px; box-shadow: inset 0 2px 10px rgba(0,0,0,0.05); border: 1px solid #dee2e6; }
.ai-msg { background: #e8f4fd; padding: 12px; border-radius: 15px 15px 15px 0; margin-bottom: 10px; border-left: 4px solid var(--accent); } .ai-msg { background: #f0f4f8; padding: 15px; border-radius: 18px 18px 18px 0; margin-bottom: 15px; border-left: 4px solid var(--accent); color: #2c3e50; }
.user-msg { background: #e2f3e5; padding: 12px; border-radius: 15px 15px 0 15px; margin-bottom: 10px; text-align: right; border-right: 4px solid var(--primary); margin-left: 20%; } .user-msg { background: #e8f5e9; padding: 15px; border-radius: 18px 18px 0 18px; margin-bottom: 15px; text-align: right; border-right: 4px solid var(--primary); margin-left: 15%; color: #1b5e20; }
.meal-card { border: none; border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.05); transition: 0.3s; margin-bottom: 15px; } .config-card { background: rgba(255,255,255,0.05); padding: 15px; border-radius: 12px; margin-bottom: 15px; }
.meal-card:hover { transform: scale(1.02); } .kcal-display { background: var(--primary); color: white; padding: 20px; border-radius: 15px; text-align: center; margin-bottom: 20px; }
.kcal-badge { background: var(--primary); color: white; padding: 5px 12px; border-radius: 20px; font-weight: bold; } pre { white-space: pre-wrap; word-wrap: break-word; font-family: inherit; margin-bottom: 0; }
</style> </style>
</head> </head>
<body> <body>
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-lg-3 config-panel shadow-lg"> <div class="col-lg-3 sidebar">
<h4 class="mb-4 text-info"><i class="fas fa-microchip me-2"></i>Configurare Bio</h4> <h4 class="mb-4 text-success fw-bold"><i class="fas fa-brain me-2"></i>NutriAI v3.0</h4>
<div class="row g-2"> <div class="config-card">
<div class="col-6 mb-3"> <div class="row g-2">
<label class="small opacity-75">Greutate (kg)</label> <div class="col-6 mb-2">
<input type="number" id="greutate" class="form-control bg-secondary text-white border-0" value="85"> <label class="small opacity-75">Greutate (kg)</label>
<input type="number" id="greutate" class="form-control form-control-sm" value="80">
</div>
<div class="col-6 mb-2">
<label class="small opacity-75">Înălțime (cm)</label>
<input type="number" id="inaltime" class="form-control form-control-sm" value="180">
</div>
<div class="col-6 mb-2">
<label class="small opacity-75">Vârstă</label>
<input type="number" id="varsta" class="form-control form-control-sm" value="30">
</div>
<div class="col-6 mb-2">
<label class="small opacity-75">Sex</label>
<select id="sex" class="form-select form-select-sm">
<option value="masculin">Masculin</option>
<option value="feminin">Feminin</option>
</select>
</div>
</div> </div>
<div class="col-6 mb-3"> <div class="mb-2">
<label class="small opacity-75">Înălțime (cm)</label> <label class="small opacity-75">Activitate</label>
<input type="number" id="inaltime" class="form-control bg-secondary text-white border-0" value="180"> <select id="activitate" class="form-select form-select-sm">
</div> <option value="1.2">Sedentar</option>
<div class="col-6 mb-3"> <option value="1.375">Activitate Ușoară</option>
<label class="small opacity-75">Vârstă</label> <option value="1.55">Moderat Activ</option>
<input type="number" id="varsta" class="form-control bg-secondary text-white border-0" value="30"> <option value="1.725">Foarte Activ</option>
</div>
<div class="col-6 mb-3">
<label class="small opacity-75">Sex</label>
<select id="sex" class="form-select bg-secondary text-white border-0">
<option value="masculin">Masculin</option>
<option value="feminin">Feminin</option>
</select> </select>
</div> </div>
</div> </div>
<div class="mb-3"> <div class="config-card">
<label class="small opacity-75">Nivel de Activitate</label> <label class="fw-bold d-block mb-2">Ajustare Obiectiv</label>
<select id="activitate" class="form-select bg-secondary text-white border-0"> <input type="range" class="form-range" id="kcalAdjust" min="-800" max="800" step="50" value="0">
<option value="1.2">Sedentar (birou, puțină mișcare)</option> <div class="d-flex justify-content-between small opacity-75">
<option value="1.375">Ușor Activ (sport 1-3 zile/săpt)</option> <span>Slăbire</span>
<option value="1.55">Moderat Activ (sport 3-5 zile/săpt)</option> <span id="sliderVal" class="text-success fw-bold">0 kcal</span>
<option value="1.725">Foarte Activ (sport zilnic, job fizic)</option> <span>Masă</span>
</select> </div>
</div> </div>
<hr class="my-4"> <div class="kcal-display shadow-sm">
<label class="fw-bold mb-2">Obiectiv: <span id="valObj" class="text-info">0</span> kcal</label> <small class="opacity-75">Țintă zilnică calculată</small>
<input type="range" class="form-range" id="sliderObj" min="-800" max="800" step="50" value="0" <h2 class="mb-0 fw-bold"><span id="totalKcal">2500</span> kcal</h2>
oninput="document.getElementById('valObj').innerText = (this.value > 0 ? '+' : '') + this.value">
<div class="d-flex justify-content-between x-small opacity-50 mb-4">
<span>Slăbire Rapidă</span>
<span>Menținere</span>
<span>Masă Musculară</span>
</div> </div>
<button onclick="initAI()" class="btn btn-info w-100 fw-bold py-3 shadow">CALCULEAZĂ ȘI PORNEȘTE AI</button> <button onclick="calculateAndSync()" class="btn btn-success w-100 fw-bold py-2 mb-3 shadow">
<i class="fas fa-sync-alt me-2"></i>RECALCULEAZĂ
</button>
</div> </div>
<div class="col-lg-9 p-4"> <div class="col-lg-9 p-4">
<div class="row"> <div class="mx-auto" style="max-width: 900px;">
<div class="col-md-5"> <div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="fw-bold mb-3"><i class="fas fa-comments me-2"></i>Chat Consultant AI</h5> <h4 class="fw-bold mb-0 text-dark"><i class="fas fa-comments me-2 text-primary"></i>Consultant Nutrițional Real-Time</h4>
<div id="chatBox" class="chat-container"> <span class="badge bg-success">Powered by Groq AI</span>
<div class="ai-msg">Salut! Sunt asistentul tău de nutriție. Completează datele din stânga și spune-mi ce dorințe ai pentru meniu!</div> </div>
</div>
<div class="input-group"> <div id="chatBox" class="chat-container mb-3">
<input type="text" id="userInput" class="form-control p-3" placeholder="Ex: Nu vreau carne de porc..."> <div class="ai-msg">
<button onclick="sendMessage()" class="btn btn-primary px-4"><i class="fas fa-paper-plane"></i></button> Bună! Sunt consultantul tău AI. Am preluat datele tale bio. <br><br>
<strong>Cum te pot ajuta astăzi?</strong> Îmi poți cere un meniu săptămânal, o listă de cumpărături sau un program de antrenament adaptat caloriilor tale.
</div> </div>
</div> </div>
<div class="col-md-7"> <div class="input-group input-group-lg shadow-sm">
<div class="d-flex justify-content-between align-items-center mb-3"> <input type="text" id="userInput" class="form-control border-0 ps-4" placeholder="Ex: Generează-mi meniul pe toată săptămâna, sunt vegetarian...">
<h5 class="fw-bold mb-0"><i class="fas fa-calendar-alt me-2"></i>Meniu Săptămânal Personalizat</h5> <button onclick="sendToGroq()" class="btn btn-primary px-4 border-0">
<div id="dayTabs"></div> <i class="fas fa-paper-plane"></i>
</div> </button>
<div id="menuContent">
</div>
</div> </div>
<p class="text-center text-muted small mt-2">AI-ul va genera meniuri detaliate cu gramaje și instrucțiuni.</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
let globalKcal = 0; const GROQ_API_KEY = "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";
let excludedFoods = []; let currentKcal = 0;
let isVegetarian = false;
function initAI() { document.getElementById('kcalAdjust').addEventListener('input', function() {
document.getElementById('sliderVal').innerText = (this.value > 0 ? '+' : '') + this.value + " kcal";
calculateAndSync();
});
function calculateAndSync() {
const g = parseFloat(document.getElementById('greutate').value); const g = parseFloat(document.getElementById('greutate').value);
const i = parseFloat(document.getElementById('inaltime').value); const i = parseFloat(document.getElementById('inaltime').value);
const v = parseFloat(document.getElementById('varsta').value); const v = parseFloat(document.getElementById('varsta').value);
const s = document.getElementById('sex').value; const s = document.getElementById('sex').value;
const act = parseFloat(document.getElementById('activitate').value); const act = parseFloat(document.getElementById('activitate').value);
const obj = parseInt(document.getElementById('sliderObj').value); const adj = parseInt(document.getElementById('kcalAdjust').value);
// BMR Mifflin-St Jeor
let bmr = (s === 'masculin') ? (10 * g) + (6.25 * i) - (5 * v) + 5 : (10 * g) + (6.25 * i) - (5 * v) - 161; let bmr = (s === 'masculin') ? (10 * g) + (6.25 * i) - (5 * v) + 5 : (10 * g) + (6.25 * i) - (5 * v) - 161;
globalKcal = Math.round((bmr * act) + obj); currentKcal = Math.round((bmr * act) + adj);
addChatMessage("ai", `Am calculat! Ai nevoie de **${globalKcal} kcal** pe zi pentru obiectivul tău. Am generat meniul de bază. Poți să-mi ceri schimbări acum!`); document.getElementById('totalKcal').innerText = currentKcal;
renderMenu();
} }
function sendMessage() { async function sendToGroq() {
const input = document.getElementById('userInput'); const input = document.getElementById('userInput');
const text = input.value.trim().toLowerCase(); const userText = input.value.trim();
if(!text) return; if(!userText) return;
addChatMessage("user", input.value); addMessage("user", userText);
input.value = ""; input.value = "";
// Logica de "Simulare AI" const loadingId = "loading-" + Date.now();
setTimeout(() => { addMessage("ai", '<div class="spinner-border spinner-border-sm text-primary"></div> AI-ul generează planul...', loadingId);
if(text.includes("fara porc") || text.includes("nu porc")) {
excludedFoods.push("porc"); try {
addChatMessage("ai", "Am înțeles. Am eliminat carnea de porc din toate zilele și am înlocuit-o cu pui sau curcan."); const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
} else if(text.includes("vegetarian")) { method: "POST",
isVegetarian = true; headers: {
addChatMessage("ai", "Configurație schimbată pe mod **Vegetarian**. Rețetele au fost actualizate."); "Authorization": `Bearer ${GROQ_API_KEY}`,
} else if(text.includes("antrenament")) { "Content-Type": "application/json"
addChatMessage("ai", "Am adăugat o secțiune de antrenament la finalul fiecărei zile."); },
} else { body: JSON.stringify({
addChatMessage("ai", "Interesant! Voi ține cont de asta în structura meniului tău."); model: "llama-3.3-70b-versatile",
} messages: [
renderMenu(); {
}, 800); role: "system",
content: `Ești un nutriționist și antrenor expert.
Date utilizator: ${currentKcal} kcal/zi necesare.
Sarcina ta: Generează meniuri săptămânale detaliate, liste de cumpărături sau planuri de antrenament.
Include gramaje precise (ex: 150g pui) și calorii per masă.
Răspunde prietenos în limba română, folosind Markdown pentru claritate.`
},
{ role: "user", content: userText }
],
temperature: 0.7
})
});
const data = await response.json();
const aiText = data.choices[0].message.content;
document.getElementById(loadingId).innerHTML = `<pre>${aiText}</pre>`;
} catch (error) {
document.getElementById(loadingId).innerText = "Eroare! Verifică dacă API Key-ul de Groq este corect.";
console.error(error);
}
} }
function addChatMessage(type, msg) { function addMessage(type, msg, id = null) {
const box = document.getElementById('chatBox'); const box = document.getElementById('chatBox');
box.innerHTML += `<div class="${type}-msg">${msg}</div>`; box.innerHTML += `<div class="${type}-msg" ${id ? `id="${id}"` : ''}>${msg}</div>`;
box.scrollTop = box.scrollHeight; box.scrollTop = box.scrollHeight;
} }
function renderMenu() { calculateAndSync();
if(globalKcal === 0) return;
const content = document.getElementById('menuContent');
// Simulare rețete dinamice
let retete = [
{ tip: "Mic Dejun", n: isVegetarian ? "Budincă de chia cu migdale" : "Ouă ochiuri cu bacon de curcan", p: 0.25 },
{ tip: "Prânz", n: isVegetarian ? "Salată de linte și avocado" : (excludedFoods.includes("porc") ? "Pui la grătar cu sparanghel" : "Costițe de porc la cuptor"), p: 0.35 },
{ tip: "Gustare", n: "Mix de nuci și fructe", p: 0.15 },
{ tip: "Cină", n: isVegetarian ? "Risotto cu hribi" : "Pește alb cu cartofi natur", p: 0.25 }
];
content.innerHTML = retete.map(r => `
<div class="card meal-card">
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<span class="badge bg-light text-primary mb-1">${r.tip}</span>
<h6 class="fw-bold mb-0">${r.n}</h6>
</div>
<div class="kcal-badge">${Math.round(globalKcal * r.p)} kcal</div>
</div>
</div>
`).join('');
}
</script> </script>
</body> </body>
</html> </html>