"Vendor folder not found. Please run 'composer install' in the server directory."]); exit; } require_once $autoloadPath; use Dompdf\Dompdf; use Dompdf\Options; // 1. Get POST Data $rawData = file_get_contents('php://input'); $data = json_decode($rawData, true); $jobDescription = $data['jobDescription'] ?? ''; $apiKey = $data['apiKey'] ?? ''; if (empty($jobDescription) || empty($apiKey)) { http_response_code(400); echo json_encode(["error" => "Missing jobDescription or apiKey in POST payload."]); exit; } // 2. Build Gemini API Request $model = "gemini-2.5-flash"; $geminiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent?key=" . $apiKey; $prompt = "You are an expert ATS CV tailor. Read the following job description and generate tailored content for my CV to maximize my chances of getting an interview. Return ONLY a valid JSON object with EXACTLY three keys: 'headline', 'summary', and 'skills'. The 'headline' should be a 5-6 word professional title relevant to the job. The 'summary' should be a 3-sentence powerful paragraph highlighting skills relevant to the job. The 'skills' should be a comma-separated list of 10 highly relevant ATS keywords. Do NOT use markdown blocks like ```json, just return raw JSON text. Job Description: " . substr($jobDescription, 0, 4000); $payload = json_encode([ "contents" => [ ["parts" => [["text" => $prompt]]] ], "generationConfig" => [ "temperature" => 0.2, // Low temperature for consistent JSON "responseMimeType" => "application/json" // Force JSON output ] ]); // 3. Call Google Gemini via cURL $ch = curl_init($geminiUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode !== 200) { http_response_code(500); echo json_encode(["error" => "Gemini API Error", "statusCode" => $httpCode, "details" => json_decode($response)]); exit; } // 4. Parse Gemini Response $responseData = json_decode($response, true); $aiText = $responseData['candidates'][0]['content']['parts'][0]['text'] ?? '{}'; // Clean markdown if Gemini still wrapped it in ```json ... ``` $aiText = str_replace(['```json', '```'], '', $aiText); $aiText = trim($aiText); $parsedJson = json_decode($aiText, true); $headline = $parsedJson['headline'] ?? "Solutions Architect & Technical Leader"; $summary = $parsedJson['summary'] ?? "Experienced professional with a strong background in software engineering and system architecture."; $skills = $parsedJson['skills'] ?? "Architecture, APIs, Cloud, Backend Systems, System Design"; // 5. Load HTML Template and Inject Data // Note: Put cv_template.html in the same directory as this script on your server $templatePath = __DIR__ . '/cv_template.html'; if (!file_exists($templatePath)) { http_response_code(500); echo json_encode(["error" => "cv_template.html not found on server."]); exit; } $html = file_get_contents($templatePath); $html = str_replace('{{JOB_HEADLINE}}', htmlspecialchars($headline), $html); $html = str_replace('{{TAILORED_SUMMARY}}', htmlspecialchars($summary), $html); $html = str_replace('{{DYNAMIC_SKILLS}}', htmlspecialchars($skills), $html); // 6. Generate PDF via Dompdf try { $options = new Options(); $options->set('isHtml5ParserEnabled', true); $options->set('defaultFont', 'Helvetica'); $options->set('isRemoteEnabled', true); $dompdf = new Dompdf($options); $dompdf->loadHtml($html); $dompdf->setPaper('A4', 'portrait'); $dompdf->render(); // 7. Return PDF as Base64 encoded string to the frontend $pdfOutput = $dompdf->output(); $base64Pdf = base64_encode($pdfOutput); echo json_encode([ "success" => true, "pdf" => $base64Pdf, "filename" => "Hamza_Ayed_Tailored_CV.pdf" ]); } catch (Exception $e) { http_response_code(500); echo json_encode(["error" => "PDF Generation Failed", "details" => $e->getMessage()]); }