This commit is contained in:
Ionel Andrei Cataon
2026-02-18 16:03:01 +02:00
parent 4383ff369e
commit 7a3190ac69

View File

@@ -3,79 +3,93 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sistem Expert Nutriție & Antrenament AI</title>
<title>Sistem Avansat Nutriție AI</title>
<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">
<style>
:root { --primary: #27ae60; --dark: #1a252f; --light: #f8f9fa; }
body { background-color: #e9ecef; font-family: 'Segoe UI', sans-serif; }
.sidebar { background: var(--dark); color: white; min-height: 100vh; padding: 30px; }
.main-card { background: white; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); padding: 30px; margin-top: 20px; }
.slider-label { display: flex; justify-content: space-between; font-weight: bold; margin-bottom: 10px; }
.day-pill { cursor: pointer; padding: 8px 15px; border-radius: 20px; background: #eee; margin: 3px; display: inline-block; transition: 0.2s; }
.day-pill.active { background: var(--primary); color: white; }
.meal-item { border-left: 5px solid var(--primary); background: var(--light); padding: 15px; border-radius: 10px; margin-bottom: 15px; }
.shopping-list { background: #fff3cd; border: 1px dashed #ffeeba; padding: 20px; border-radius: 10px; }
:root { --primary: #27ae60; --accent: #3498db; --dark: #1e272e; }
body { background: #f1f2f6; font-family: 'Segoe UI', sans-serif; }
.config-panel { background: var(--dark); color: white; min-height: 100vh; padding: 25px; border-radius: 0 30px 30px 0; }
.chat-container { height: 400px; overflow-y: auto; background: #fff; border-radius: 15px; padding: 20px; border: 1px solid #ddd; margin-bottom: 15px; }
.ai-msg { background: #e8f4fd; padding: 12px; border-radius: 15px 15px 15px 0; margin-bottom: 10px; border-left: 4px solid var(--accent); }
.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%; }
.meal-card { border: none; border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.05); transition: 0.3s; margin-bottom: 15px; }
.meal-card:hover { transform: scale(1.02); }
.kcal-badge { background: var(--primary); color: white; padding: 5px 12px; border-radius: 20px; font-weight: bold; }
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-lg-3 sidebar">
<h4 class="mb-4 text-success"><i class="fas fa-microchip me-2"></i>NutriControl AI</h4>
<div class="col-lg-3 config-panel shadow-lg">
<h4 class="mb-4 text-info"><i class="fas fa-microchip me-2"></i>Configurare Bio</h4>
<div class="row g-2">
<div class="col-6 mb-3">
<label class="small opacity-75">Greutate (kg)</label>
<input type="number" id="greutate" class="form-control bg-secondary text-white border-0" value="85">
</div>
<div class="col-6 mb-3">
<label class="small opacity-75">Înălțime (cm)</label>
<input type="number" id="inaltime" class="form-control bg-secondary text-white border-0" value="180">
</div>
<div class="col-6 mb-3">
<label class="small opacity-75">Vârstă</label>
<input type="number" id="varsta" class="form-control bg-secondary text-white border-0" value="30">
</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>
</div>
</div>
<div class="mb-3">
<label class="form-label">Greutate (kg)</label>
<input type="number" id="greutate" class="form-control bg-dark text-white border-0" value="80">
</div>
<div class="mb-3">
<label class="form-label">Înălțime (cm)</label>
<input type="number" id="inaltime" class="form-control bg-dark text-white border-0" value="180">
<label class="small opacity-75">Nivel de Activitate</label>
<select id="activitate" class="form-select bg-secondary text-white border-0">
<option value="1.2">Sedentar (birou, puțină mișcare)</option>
<option value="1.375">Ușor Activ (sport 1-3 zile/săpt)</option>
<option value="1.55">Moderat Activ (sport 3-5 zile/săpt)</option>
<option value="1.725">Foarte Activ (sport zilnic, job fizic)</option>
</select>
</div>
<hr class="my-4">
<label class="fw-bold mb-2">Obiectiv: <span id="valObj" class="text-info">0</span> kcal</label>
<input type="range" class="form-range" id="sliderObj" min="-800" max="800" step="50" value="0"
oninput="document.getElementById('valObj').innerText = (this.value > 0 ? '+' : '') + this.value">
<div class="mb-4">
<div class="slider-label">
<span>Deficit/Surplus</span>
<span id="sliderVal" class="text-success">0 kcal</span>
</div>
<input type="range" class="form-range" id="kcalAdjust" min="-1000" max="1000" step="50" value="0"
oninput="document.getElementById('sliderVal').innerText = this.value + ' kcal'">
<div class="d-flex justify-content-between small opacity-50">
<span>Slăbire</span>
<div class="d-flex justify-content-between x-small opacity-50 mb-4">
<span>Slăbire Rapidă</span>
<span>Menținere</span>
<span>Masă</span>
</div>
<span>Masă Musculară</span>
</div>
<button onclick="updateAI()" class="btn btn-success w-100 fw-bold p-3">ACTUALIZEAZĂ PLANUL</button>
<button onclick="initAI()" class="btn btn-info w-100 fw-bold py-3 shadow">CALCULEAZĂ ȘI PORNEȘTE AI</button>
</div>
<div class="col-lg-9 p-4">
<div id="welcomeScreen" class="text-center py-5">
<i class="fas fa-chart-line fa-4x text-muted mb-3"></i>
<h2>Configurează-ți planul în stânga</h2>
<div class="row">
<div class="col-md-5">
<h5 class="fw-bold mb-3"><i class="fas fa-comments me-2"></i>Chat Consultant AI</h5>
<div id="chatBox" class="chat-container">
<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 class="input-group">
<input type="text" id="userInput" class="form-control p-3" placeholder="Ex: Nu vreau carne de porc...">
<button onclick="sendMessage()" class="btn btn-primary px-4"><i class="fas fa-paper-plane"></i></button>
</div>
</div>
<div id="dashboard" style="display: none;">
<div class="row">
<div class="col-md-8">
<div class="main-card">
<div class="d-flex justify-content-between mb-4">
<h3>Meniu Săptămânal</h3>
<div id="daysRow"></div>
<div class="col-md-7">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="fw-bold mb-0"><i class="fas fa-calendar-alt me-2"></i>Meniu Săptămânal Personalizat</h5>
<div id="dayTabs"></div>
</div>
<div id="mealContainer"></div>
</div>
</div>
<div class="col-md-4">
<div class="main-card shopping-list">
<h5 class="fw-bold"><i class="fas fa-shopping-basket me-2"></i>Listă Cumpărături</h5>
<ul id="groceryList" class="list-unstyled mt-3"></ul>
</div>
<div id="trainingSection" class="mt-3"></div>
<div id="menuContent">
</div>
</div>
</div>
@@ -84,69 +98,81 @@
</div>
<script>
const db = [
{ d: "Luni", m: ["Ovăz cu afine", "Pui cu orez și broccoli", "Iaurt cu nuci", "Salată cu ton"] },
{ d: "Marți", m: ["Omletă cu spanac", "Paste integrale cu pesto", "Măr cu migdale", "Curcan la grătar"] },
{ d: "Miercuri", m: ["Smoothie proteic", "Vită cu fasole verde", "Brânză cottage", "Pește cu lămâie"] },
// ... restul zilelor se repeta logic
];
let globalKcal = 0;
let excludedFoods = [];
let isVegetarian = false;
let currentDay = 0;
let baseKcal = 0;
function updateAI() {
function initAI() {
const g = parseFloat(document.getElementById('greutate').value);
const i = parseFloat(document.getElementById('inaltime').value);
const adjust = parseInt(document.getElementById('kcalAdjust').value);
const v = parseFloat(document.getElementById('varsta').value);
const s = document.getElementById('sex').value;
const act = parseFloat(document.getElementById('activitate').value);
const obj = parseInt(document.getElementById('sliderObj').value);
// Formula simplificată BMR
baseKcal = Math.round(((10 * g) + (6.25 * i) - (5 * 30) + 5) * 1.4);
const finalKcal = baseKcal + adjust;
// BMR Mifflin-St Jeor
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);
document.getElementById('welcomeScreen').style.display = 'none';
document.getElementById('dashboard').style.display = 'block';
renderDays();
showMeals(0, finalKcal);
generateGroceries();
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!`);
renderMenu();
}
function renderDays() {
document.getElementById('daysRow').innerHTML = ["L", "M", "Mi", "J", "V", "S", "D"].map((d, i) =>
`<span class="day-pill ${i === currentDay ? 'active' : ''}" onclick="selectDay(${i})">${d}</span>`
).join('');
function sendMessage() {
const input = document.getElementById('userInput');
const text = input.value.trim().toLowerCase();
if(!text) return;
addChatMessage("user", input.value);
input.value = "";
// Logica de "Simulare AI"
setTimeout(() => {
if(text.includes("fara porc") || text.includes("nu porc")) {
excludedFoods.push("porc");
addChatMessage("ai", "Am înțeles. Am eliminat carnea de porc din toate zilele și am înlocuit-o cu pui sau curcan.");
} else if(text.includes("vegetarian")) {
isVegetarian = true;
addChatMessage("ai", "Configurație schimbată pe mod **Vegetarian**. Rețetele au fost actualizate.");
} else if(text.includes("antrenament")) {
addChatMessage("ai", "Am adăugat o secțiune de antrenament la finalul fiecărei zile.");
} else {
addChatMessage("ai", "Interesant! Voi ține cont de asta în structura meniului tău.");
}
renderMenu();
}, 800);
}
function selectDay(i) {
currentDay = i;
const adjust = parseInt(document.getElementById('kcalAdjust').value);
showMeals(i, baseKcal + adjust);
renderDays();
function addChatMessage(type, msg) {
const box = document.getElementById('chatBox');
box.innerHTML += `<div class="${type}-msg">${msg}</div>`;
box.scrollTop = box.scrollHeight;
}
function showMeals(dayIdx, total) {
const meals = ["Mic Dejun (25%)", "Prânz (35%)", "Gustare (15%)", "Cină (25%)"];
const dayData = db[dayIdx % 3]; // Ciclam datele pentru demo
function renderMenu() {
if(globalKcal === 0) return;
const content = document.getElementById('menuContent');
let html = `<h5>Țintă zilnică: <strong>${total} kcal</strong></h5><hr>`;
meals.forEach((m, i) => {
const perc = i === 0 || i === 3 ? 0.25 : (i === 1 ? 0.35 : 0.15);
html += `
<div class="meal-item d-flex justify-content-between">
<div><strong>${m}</strong><br>${dayData.m[i]}</div>
<div class="text-success fw-bold">${Math.round(total * perc)} kcal</div>
</div>`;
});
document.getElementById('mealContainer').innerHTML = html;
}
// 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 }
];
function generateGroceries() {
const items = ["Pungi de Ovăz", "Piept de Pui (1.5kg)", "Orez Brun", "Bax de Iaurt", "Migdale & Nuci", "Legume Congelate", "Fructe de sezon"];
document.getElementById('groceryList').innerHTML = items.map(it =>
`<li class="mb-2"><i class="far fa-square me-2"></i>${it}</li>`
).join('');
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>
</body>
</html>