Initial commit: LinkedIn Analyzer with Gemini 2.5 Flash and PHP Backend

This commit is contained in:
Hamza-Ayed
2026-05-17 01:28:17 +03:00
commit 8445affc78
18 changed files with 3323 additions and 0 deletions

7
server/composer.json Normal file
View File

@@ -0,0 +1,7 @@
{
"name": "hamza/cv-generator",
"description": "Dynamic ATS-Optimized CV Generator",
"require": {
"dompdf/dompdf": "^3.0"
}
}

169
server/cv_template.html Normal file
View File

@@ -0,0 +1,169 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
/*
* CSS Optimized for Dompdf / mPDF / TCPDF
* Avoids flexbox, uses standard block/inline styling for flawless PDF generation.
*/
body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 13px;
color: #222;
line-height: 1.5;
margin: 0;
padding: 20px 40px;
}
.header {
text-align: center;
border-bottom: 2px solid #1a237e;
padding-bottom: 15px;
margin-bottom: 20px;
}
h1 {
font-size: 28px;
color: #1a237e;
margin: 0 0 5px 0;
text-transform: uppercase;
letter-spacing: 1px;
}
.headline {
font-size: 16px;
font-weight: bold;
color: #424242;
margin-bottom: 5px;
}
.contact {
font-size: 12px;
color: #555;
}
.section-title {
font-size: 15px;
font-weight: bold;
color: #1a237e;
border-bottom: 1px solid #ddd;
margin-top: 20px;
margin-bottom: 10px;
padding-bottom: 4px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
p { margin: 0 0 10px 0; text-align: justify; }
.job-block { margin-bottom: 15px; }
.job-header {
width: 100%;
margin-bottom: 5px;
}
.job-title {
font-weight: bold;
font-size: 14px;
color: #222;
float: left;
}
.job-meta {
font-size: 12px;
color: #1a237e;
font-weight: bold;
float: right;
}
.clear { clear: both; }
ul { margin: 5px 0 10px 0; padding-left: 20px; }
li { margin-bottom: 6px; text-align: justify; }
</style>
</head>
<body>
<div class="header">
<h1>Hamza Ayed</h1>
<!-- PHP WILL INJECT THE AI-GENERATED HEADLINE HERE -->
<div class="headline">{{JOB_HEADLINE}}</div>
<div class="contact">
Amman, Jordan | +962 79 858 3052 | hamzaayed@intaleqapp.com | linkedin.com/in/hamza-ayed
</div>
</div>
<div class="section-title">Professional Summary</div>
<!-- PHP WILL INJECT THE AI-GENERATED SUMMARY HERE -->
<p>{{TAILORED_SUMMARY}}</p>
<div class="section-title">Core Competencies & Skills</div>
<!-- PHP WILL INJECT ATS KEYWORDS HERE -->
<p><strong>Targeted Expertise:</strong> {{DYNAMIC_SKILLS}}</p>
<p><strong>Technologies:</strong> Flutter/Dart, PHP, Python (FastAPI/Flask), Node.js, MySQL, PostgreSQL, AWS/Cloud Infrastructure, Git, Docker.</p>
<p><strong>Domains:</strong> System Architecture, Distributed Systems, GIS/Mapping (OSM), FinTech (Payment Gateways), AI/ML Integration, Zero-Trust Security.</p>
<div class="section-title">Professional Experience</div>
<div class="job-block">
<div class="job-header">
<div class="job-title">CTO & Solutions Architect — Intaleq</div>
<div class="job-meta">Jan 2025 Present | Syria / Remote</div>
<div class="clear"></div>
</div>
<ul>
<li>Led the full-stack architecture of a smart transportation ecosystem supporting 1,800+ drivers and 2,500+ riders.</li>
<li>Built a proprietary mapping platform (IntaleqMaps) on OpenStreetMap, eliminating reliance on Google Maps API and saving $10,000+/month in operational costs.</li>
<li>Designed secure, custom payment infrastructure for environments lacking standard payment APIs, ensuring high-availability transaction integrity.</li>
</ul>
</div>
<div class="job-block">
<div class="job-header">
<div class="job-title">Co-Founder & Lead Developer — Tripz Egypt</div>
<div class="job-meta">Jan 2024 Present | Cairo / Remote</div>
<div class="clear"></div>
</div>
<ul>
<li>Architected Egypt's homegrown ride-hailing platform, managing the entire distributed ecosystem with real-time tracking and dispatching.</li>
<li>Implemented robust microservices for real-time driver/rider matching and route optimization using event-driven architecture.</li>
</ul>
</div>
<div class="job-block">
<div class="job-header">
<div class="job-title">Mobile Solutions Architect — Freelance</div>
<div class="job-meta">Jan 2017 Dec 2023 | Jordan / Remote</div>
<div class="clear"></div>
</div>
<ul>
<li>Delivered 25+ production enterprise applications across GIS, FinTech, HR, and utilities for clients across the MENA region.</li>
<li>Integrated AI vision models for document analysis (KYC) and automated invoice processing pipelines.</li>
</ul>
</div>
<div class="job-block">
<div class="job-header">
<div class="job-title">Operations & Logistics Officer — Jordan Armed Forces</div>
<div class="job-meta">Oct 2003 Nov 2023 | Jordan</div>
<div class="clear"></div>
</div>
<ul>
<li>Retired Lieutenant Colonel. Directed logistics and crisis management operations, leading teams of 50+ personnel.</li>
<li>Applied rigorous, security-first methodologies to organizational leadership, disaster recovery, and operational planning.</li>
</ul>
</div>
<div class="section-title">Education & Certifications</div>
<ul>
<li><strong>BS Mathematics</strong>, Mutah University (20032007)</li>
<li>Google Data Analytics Professional Certificate</li>
<li>IBM Data Science Professional Certificate</li>
<li>Meta Mobile Development Certificate</li>
<li><em>Total of 51 professional certifications across software engineering, AI, and enterprise architecture.</em></li>
</ul>
</body>
</html>

134
server/generate_cv.php Normal file
View File

@@ -0,0 +1,134 @@
<?php
// ============================================================================
// Dynamic ATS-Optimized CV Generator (Backend)
// ============================================================================
// Allow CORS from browser extension
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
// Ensure composer dependencies are installed
$autoloadPath = __DIR__ . '/vendor/autoload.php';
if (!file_exists($autoloadPath)) {
http_response_code(500);
echo json_encode(["error" => "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()]);
}