false, 'message' => 'Invalid request method']); exit; } if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) { echo json_encode(['success' => false, 'message' => 'Upload failed or no image provided']); exit; } $type = $_POST['type'] ?? 'ktp'; // 'ktp' or 'kk' $imagePath = $_FILES['image']['tmp_name']; $imageData = base64_encode(file_get_contents($imagePath)); $mimeType = mime_content_type($imagePath); // Construct Prompt based on Type if ($type === 'kk') { $promptText = "Extract strictly from this Indonesian Family Card (Kartu Keluarga). Return ONLY a raw JSON object with these keys: 'no_kk' (16 digits), 'kepala_keluarga' (Name), 'alamat', 'rt', 'rw', 'desa', 'kecamatan', 'kabupaten', 'provinsi', 'kode_pos', 'anggota': [ { 'nik': '...', 'nama': '...', 'hubungan': '...' } ] (Array of all family members found in the table. 'hubungan' examples: KEPALA KELUARGA, ISTRI, ANAK, FAMILI LAIN). Value must be string. If not found, use empty string."; } else { // Default to KTP $promptText = "Extract data from this Indonesian KTP. Return ONLY a raw JSON object with keys: 'nik' (16 digits), 'nama' (Name), 'tempat_lh' (Place of Birth), 'tgl_lh' (YYYY-MM-DD), 'je_kel' (LK/PR), 'alamat' (Street only), 'rt', 'rw', 'desa' (Kel/Desa), 'kecamatan', 'kabupaten' (or Kota), 'provinsi', 'agama', 'status' (Sudah/Belum/Cerai Hidup/Cerai Mati), 'pekerjaan', 'kewarganegaraan' (WNI/WNA). Clean up text. If field is unclear, return empty string."; } // Payload for Ollama App $data = [ "model" => "qwen2.5vl:3b", "messages" => [ [ "role" => "user", "content" => $promptText, "images" => [$imageData] ] ], "stream" => false ]; // Send Request $ch = curl_init(OLLAMA_API_URL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { echo json_encode(['success' => false, 'message' => 'CURL Error: ' . $error]); exit; } $result = json_decode($response, true); // Debugging check if (isset($result['error'])) { echo json_encode(['success' => false, 'message' => 'API Error: ' . $result['error']['message']]); exit; } if (!isset($result['message']['content'])) { echo json_encode(['success' => false, 'message' => 'No text returned from AI', 'raw' => $result]); exit; } // Parse AI Response $rawText = $result['message']['content']; // Remove Markdown Code Blocks if any (```json ... ```) $cleanJson = preg_replace('/^```json\s*|\s*```$/', '', trim($rawText)); $parsedData = json_decode($cleanJson, true); if (json_last_error() !== JSON_ERROR_NONE) { // Fallback: try to find JSON object structure in text if (preg_match('/\{.*\}/s', $cleanJson, $matches)) { $parsedData = json_decode($matches[0], true); } } if (!$parsedData) { echo json_encode(['success' => false, 'message' => 'Failed to parse AI response', 'raw_text' => $rawText]); exit; } if ($type === 'ktp') { // 1. Parse Status Perkawinan if (!empty($parsedData['status'])) { $st = strtoupper($parsedData['status']); if (strpos($st, 'BELUM') !== false) { $parsedData['status'] = 'Belum'; } elseif (strpos($st, 'CERAI MATI') !== false) { $parsedData['status'] = 'Cerai Mati'; } elseif (strpos($st, 'CERAI HIDUP') !== false) { $parsedData['status'] = 'Cerai Hidup'; } elseif (strpos($st, 'KAWIN') !== false) { $parsedData['status'] = 'Sudah'; } } // 2. Parse Jenis Kelamin if (!empty($parsedData['je_kel'])) { $jk = strtoupper($parsedData['je_kel']); if (strpos($jk, 'LAKI') !== false || $jk === 'L') { $parsedData['je_kel'] = 'LK'; } elseif (strpos($jk, 'PEREMPUAN') !== false || $jk === 'P') { $parsedData['je_kel'] = 'PR'; } } // 3. Parse Tempat & Tanggal Lahir (KTP format: "TEMPAT, DD-MM-YYYY") if (!empty($parsedData['tempat_lh'])) { $ttl = $parsedData['tempat_lh']; if (strpos($ttl, ',') !== false) { [$tempat, $tgl] = explode(',', $ttl, 2); $parsedData['tempat_lh'] = trim($tempat); if (empty($parsedData['tgl_lh'])) { $parsedData['tgl_lh'] = trim($tgl); } } } // 4. Format Tanggal Lahir to YYYY-MM-DD for HTML input[type=date] if (!empty($parsedData['tgl_lh'])) { $tgl_lh = trim($parsedData['tgl_lh']); // If it looks like DD-MM-YYYY or DD/MM/YYYY if (preg_match('/^(\d{2})[\/\-](\d{2})[\/\-](\d{4})$/', $tgl_lh, $matches)) { $parsedData['tgl_lh'] = $matches[3] . '-' . $matches[2] . '-' . $matches[1]; } } } echo json_encode(['success' => true, 'data' => $parsedData]); ?>