133 lines
5.4 KiB
PHP
133 lines
5.4 KiB
PHP
<?php
|
|
header('Content-Type: application/json');
|
|
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
|
|
|
$debugFile = __DIR__ . '/analyze_debug.log';
|
|
function debugLog($msg) {
|
|
global $debugFile;
|
|
file_put_contents($debugFile, "[" . date('Y-m-d H:i:s') . "] " . $msg . "\n", FILE_APPEND);
|
|
}
|
|
|
|
$rawInput = file_get_contents('php://input');
|
|
$data = json_decode($rawInput, true);
|
|
$image = $data['image'] ?? null;
|
|
$barcode = $data['barcode'] ?? null;
|
|
|
|
debugLog("Request received. Barcode: " . ($barcode ?? 'none') . ", Image size: " . ($image ? strlen($image) : 0));
|
|
|
|
if (!$image && !$barcode) {
|
|
debugLog("Error: No image or barcode provided");
|
|
echo json_encode(['success' => false, 'error' => 'No image or barcode provided']);
|
|
exit;
|
|
}
|
|
|
|
$productData = null;
|
|
$errorDetails = null;
|
|
|
|
// Try Barcode Lookup via Open Food Facts if barcode is present
|
|
if ($barcode) {
|
|
debugLog("Attempting Open Food Facts lookup for $barcode");
|
|
$url = "https://world.openfoodfacts.org/api/v0/product/" . urlencode($barcode) . ".json";
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
|
curl_setopt($ch, CURLOPT_USERAGENT, 'HomePantryTracker/1.0');
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode === 200 && $response) {
|
|
$offData = json_decode($response, true);
|
|
if (isset($offData['status']) && $offData['status'] == 1) {
|
|
$p = $offData['product'];
|
|
$productData = [
|
|
'name' => $p['product_name'] ?? ($p['product_name_en'] ?? 'Unknown Product'),
|
|
'category' => 'Pantry', // Default
|
|
'quantity' => $p['quantity'] ?? '',
|
|
'expiration_date' => null
|
|
];
|
|
debugLog("Barcode found: " . $productData['name']);
|
|
|
|
// Try to map category
|
|
if (!empty($p['categories_tags'])) {
|
|
$tags = implode(' ', $p['categories_tags']);
|
|
if (stripos($tags, 'dairy') !== false || stripos($tags, 'milk') !== false) $productData['category'] = 'Dairy';
|
|
elseif (stripos($tags, 'meat') !== false) $productData['category'] = 'Meat';
|
|
elseif (stripos($tags, 'bakery') !== false || stripos($tags, 'bread') !== false) $productData['category'] = 'Bakery';
|
|
elseif (stripos($tags, 'fruit') !== false || stripos($tags, 'vegetable') !== false) $productData['category'] = 'Produce';
|
|
elseif (stripos($tags, 'frozen') !== false) $productData['category'] = 'Frozen';
|
|
}
|
|
} else {
|
|
debugLog("Barcode not found in Open Food Facts");
|
|
}
|
|
} else {
|
|
debugLog("Open Food Facts API error: $httpCode");
|
|
}
|
|
}
|
|
|
|
// If barcode lookup failed or we have an image, use AI
|
|
if (!$productData) {
|
|
debugLog("Using AI for identification...");
|
|
$prompt = "You are a professional pantry organizer. Identify the product from the image provided.
|
|
Return ONLY a valid JSON object.
|
|
Keys:
|
|
- name: Specific brand and product name.
|
|
- category: Dairy, Meat, Bakery, Produce, Pantry, Frozen.
|
|
- quantity: e.g., '1.5 L', '500g'.
|
|
- expiration_date: Look for 'Best Before', 'Use By', or 'EXP' date in YYYY-MM-DD format, or null.
|
|
If the package is not in English, translate name/category to English.";
|
|
|
|
if ($image) {
|
|
// Use "Simple" approach: data URL directly in the content string
|
|
$content = $prompt . "\nAnalyze this image: " . $image;
|
|
$messages = [
|
|
['role' => 'user', 'content' => $content]
|
|
];
|
|
} else {
|
|
$messages = [
|
|
['role' => 'user', 'content' => $prompt . " Product barcode: $barcode"]
|
|
];
|
|
}
|
|
|
|
$resp = LocalAIApi::createResponse([
|
|
'input' => $messages,
|
|
'temperature' => 0.1
|
|
]);
|
|
|
|
if (!empty($resp['success'])) {
|
|
debugLog("AI response successful");
|
|
$result = LocalAIApi::decodeJsonFromResponse($resp);
|
|
if ($result) {
|
|
$productData = $result;
|
|
} else {
|
|
$text = LocalAIApi::extractText($resp);
|
|
debugLog("AI returned text instead of JSON. Extracting...");
|
|
if (preg_match('/\{.*\}/s', $text, $matches)) {
|
|
$productData = json_decode($matches[0], true);
|
|
} else {
|
|
$errorDetails = "AI returned text instead of JSON: " . substr($text, 0, 100);
|
|
debugLog("Error: $errorDetails");
|
|
}
|
|
}
|
|
} else {
|
|
$errorDetails = $resp['error'] ?? $resp['message'] ?? 'AI request failed';
|
|
$httpStatus = $resp['status'] ?? 'unknown';
|
|
debugLog("AI Request failed. Status: $httpStatus, Error: $errorDetails");
|
|
|
|
if (isset($resp['response'])) {
|
|
debugLog("Full proxy response: " . json_encode($resp['response']));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($productData) {
|
|
if (isset($productData['expiration_date']) && ($productData['expiration_date'] === 'null' || $productData['expiration_date'] === '')) {
|
|
$productData['expiration_date'] = null;
|
|
}
|
|
debugLog("Returning success for " . ($productData['name'] ?? 'unknown'));
|
|
echo json_encode(['success' => true, 'data' => $productData]);
|
|
} else {
|
|
debugLog("Returning failure: " . ($errorDetails ?? 'Could not identify product'));
|
|
echo json_encode(['success' => false, 'error' => $errorDetails ?: 'Could not identify product']);
|
|
} |