diff --git a/api/login.php b/api/login.php index d2f3b6d..03ac5d5 100644 --- a/api/login.php +++ b/api/login.php @@ -6,19 +6,19 @@ $data = json_decode(file_get_contents('php://input'), true); $email = $data['email'] ?? ''; $password = $data['password'] ?? ''; -if (empty($email) || empty($password)) { +if ($email === '' || $password === '') { echo json_encode(['success' => false, 'error' => 'Email and password are required.']); exit; } try { - $pdo = db(); - $stmt = $pdo->prepare("SELECT id, password_hash FROM users WHERE email = ?"); + $stmt = db()->prepare("SELECT id, email, password FROM users WHERE email = ?"); $stmt->execute([$email]); - $user = $stmt->fetch(); + $user = $stmt->fetch(PDO::FETCH_ASSOC); - if ($user && password_verify($password, $user['password_hash'])) { - login_user($user['id']); + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['email'] = $user['email']; echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'error' => 'Invalid email or password.']); diff --git a/api/register.php b/api/register.php index 4082168..3379991 100644 --- a/api/register.php +++ b/api/register.php @@ -6,7 +6,7 @@ $data = json_decode(file_get_contents('php://input'), true); $email = $data['email'] ?? ''; $password = $data['password'] ?? ''; -if (empty($email) || empty($password)) { +if ($email === '' || $password === '') { echo json_encode(['success' => false, 'error' => 'Email and password are required.']); exit; } @@ -16,25 +16,19 @@ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { exit; } +$hashedPassword = password_hash($password, PASSWORD_DEFAULT); + try { - $pdo = db(); - - // Check if user already exists - $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?"); - $stmt->execute([$email]); - if ($stmt->fetch()) { - echo json_encode(['success' => false, 'error' => 'Email already registered.']); - exit; + $stmt = db()->prepare("INSERT INTO users (email, password) VALUES (?, ?)"); + if ($stmt->execute([$email, $hashedPassword])) { + $_SESSION['user_id'] = db()->lastInsertId(); + $_SESSION['email'] = $email; + echo json_encode(['success' => true]); } - - $password_hash = password_hash($password, PASSWORD_DEFAULT); - $stmt = $pdo->prepare("INSERT INTO users (email, password_hash) VALUES (?, ?)"); - $stmt->execute([$email, $password_hash]); - - $user_id = $pdo->lastInsertId(); - login_user($user_id); - - echo json_encode(['success' => true]); } catch (PDOException $e) { - echo json_encode(['success' => false, 'error' => 'Database error: ' . $e->getMessage()]); + if ($e->getCode() == 23000) { + echo json_encode(['success' => false, 'error' => 'Email is already registered.']); + } else { + echo json_encode(['success' => false, 'error' => 'Database error: ' . $e->getMessage()]); + } } diff --git a/api/scan_recipe.php b/api/scan_recipe.php index 8716cca..fdf32d6 100644 --- a/api/scan_recipe.php +++ b/api/scan_recipe.php @@ -20,20 +20,20 @@ $imageType = $_FILES['image']['type']; file_put_contents(__DIR__ . '/scan_debug.log', date('Y-m-d H:i:s') . " Processing image: type=$imageType, size=$imageSize bytes" . PHP_EOL, FILE_APPEND); file_put_contents(__DIR__ . '/scan_debug.log', date('Y-m-d H:i:s') . " Data URL prefix: " . substr("data:$imageType;base64,$imageData", 0, 50) . "..." . PHP_EOL, FILE_APPEND); -$prompt = "Analyze this image. If it's a photo of a dish, identify what it is and generate a possible recipe for it. If it's a photo of a written recipe, extract the information. -Extract or generate the following information in JSON format: -- name: The name of the dish/recipe -- category: One of 'Drinks', 'Breakfast', 'Dinner', 'Appetizers' -- ingredients: An array of objects, each with: - - name: Name of the ingredient +$prompt = "Analyze this image. If it's a photo of a dish, identify what it is and create a possible recipe for it. If it's a photo of a written recipe, extract the information from it. +Provide the information in JSON format IN ENGLISH: +- name: Dish/recipe name +- category: One of the following values: 'Drinks', 'Breakfast', 'Dinner', 'Appetizers' +- ingredients: Array of objects, each containing: + - name: Ingredient name - quantity: Numeric quantity (float) - - unit: Unit of measurement (e.g., 'g', 'kg', 'ml', 'l', 'piece', 'pack') -- guests: The default number of guests/servings the recipe is for (integer) + - unit: Unit of measurement (e.g., 'g', 'kg', 'ml', 'l', 'pcs', 'pack') +- guests: Default number of guests/portions (integer) -Important: -1. The quantities should be for 1 person if possible, or for the number of guests specified. If you're generating a recipe for a dish, default to 1 or 2 guests. +Important: +1. Quantities should be specified per 1 person if possible. If you are creating a recipe for a dish, default to 1 or 2 guests. 2. Return ONLY the JSON object. -3. If you can't determine something, provide a best guess or null."; +3. If something cannot be determined, make the most accurate assumption or specify null."; try { $response = LocalAIApi::createResponse([ diff --git a/assets/js/main.js b/assets/js/main.js index 02cd044..407f56b 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -117,7 +117,7 @@ const app = { } } catch (error) { console.error('Error:', error); - app.dom.recipeCardsContainer.innerHTML = '

Could not connect to the server.

'; + app.dom.recipeCardsContainer.innerHTML = '

Failed to connect to the server.

'; } }, async saveRecipe(formData) { @@ -191,7 +191,10 @@ const app = { if (recipe.category) { const categoryLabel = document.createElement('div'); categoryLabel.className = 'recipe-category-label'; - categoryLabel.textContent = recipe.category; + categoryLabel.textContent = recipe.category === 'Drinks' ? 'Drinks' : + recipe.category === 'Breakfast' ? 'Breakfast' : + recipe.category === 'Dinner' ? 'Lunch/Dinner' : + recipe.category === 'Appetizers' ? 'Appetizers' : recipe.category; titleWrapper.appendChild(categoryLabel); } @@ -280,7 +283,7 @@ const app = { } const item = combinedIngredients.get(key); item.additionalQty += prod.quantity; - const source = prod.source || 'Additional product'; + const source = prod.source || 'Add. product'; if (!item.sources.includes(source)) { item.sources.push(source); } @@ -292,10 +295,10 @@ const app = { // 3. Group for display const groups = { - 'Food': { ingredients: [] }, - 'Drinks': { ingredients: [] }, - 'Cooking and serving': { ingredients: [] }, - 'Tableware and consumables': { ingredients: [] } + 'Food': { label: 'Food', ingredients: [] }, + 'Drinks': { label: 'Drinks', ingredients: [] }, + 'Cooking and serving': { label: 'Kitchen & serving', ingredients: [] }, + 'Tableware and consumables': { label: 'Tableware & consumables', ingredients: [] } }; combinedIngredients.forEach((item, key) => { @@ -321,7 +324,7 @@ const app = { const group = groups[groupName]; if (group.ingredients.length > 0) { totalIngredients += group.ingredients.length; - html += `

${groupName}

`; + html += `

${group.label}

`; html += '