CodeAntidote's picture
Replace local model with Cloudflare resume AI
7340c6b verified
Raw History Blame Contribute Delete
5.09 kB
/* =========================================================
JOBALIGN AI CLIENT
A product by John_D
Resume generation now runs through the
Cloudflare Worker backend.
No local LLM download.
No WebGPU.
No WASM model.
========================================================= */
const JOBALIGN_BACKEND =
"https://jobalign-adzuna-proxy.darbymjohn.workers.dev";
/* =========================================================
STATUS
========================================================= */
function setAIStatus(
message,
type = "normal"
) {
const status =
document.getElementById(
"generationStatus"
);
if (!status) {
return;
}
let className = "";
if (type === "success") {
className =
"success-text";
} else if (type === "error") {
className =
"danger-text";
} else if (type === "warning") {
className =
"warning-text";
}
status.innerHTML = `
<div class="status-dot"></div>
<span class="${className}">
${escapeHTML(message)}
</span>
`;
}
/* =========================================================
GENERATE RESUME
========================================================= */
async function generateResume({
resume,
jobDescription,
jobTitle,
company,
location
}) {
if (
!resume ||
resume.trim().length < 100
) {
throw new Error(
"Master resume is missing."
);
}
if (
!jobDescription ||
jobDescription.trim().length < 100
) {
throw new Error(
"Job description is missing."
);
}
setAIStatus(
"Analyzing job and rebuilding resume..."
);
const response =
await fetch(
JOBALIGN_BACKEND + "/resume",
{
method:
"POST",
headers: {
"Content-Type":
"application/json",
"Accept":
"application/json"
},
body:
JSON.stringify({
resume:
resume,
jobDescription:
jobDescription,
jobTitle:
jobTitle,
company:
company,
location:
location
})
}
);
let data;
try {
data =
await response.json();
} catch (error) {
throw new Error(
"Resume service returned an unreadable response."
);
}
if (!response.ok) {
const details =
data.details
? " " + data.details
: "";
throw new Error(
(
data.error ||
"Resume generation failed."
) +
details
);
}
if (
!data.ok ||
!data.resume
) {
throw new Error(
"Resume service did not return a completed resume."
);
}
const generatedResume =
String(
data.resume
).trim();
if (
generatedResume.length < 300
) {
throw new Error(
"The generated resume was incomplete."
);
}
setAIStatus(
"Targeted resume generated",
"success"
);
return generatedResume;
}
/* =========================================================
OPTIONAL HEALTH CHECK
========================================================= */
async function checkBackend() {
try {
const response =
await fetch(
JOBALIGN_BACKEND +
"/health"
);
const data =
await response.json();
return Boolean(
response.ok &&
data.ok &&
data.aiConfigured
);
} catch (error) {
console.error(
"JobAlign backend health check failed:",
error
);
return false;
}
}
/* =========================================================
HTML SAFETY
========================================================= */
function escapeHTML(
value
) {
const element =
document.createElement(
"div"
);
element.textContent =
String(
value || ""
);
return element.innerHTML;
}
/* =========================================================
EXPOSE TO APP.JS
========================================================= */
window.JobAlignAI = {
generateResume:
generateResume,
checkBackend:
checkBackend,
mode:
"cloudflare-workers-ai"
};
window.dispatchEvent(
new CustomEvent(
"jobalign-ai-ready"
)
);