JIT
creating a pdf template for job applications with automated processing
create a basic PDF template for a job application - this will be generated and populated by a background process, and should be the final 'report' style output for the hiring manager and interviewer: /************************************************ * Enhanced Applicant → Structured PDF → Email * Added: Test Mode (last submission) & Manual Mode (all submissions) ************************************************/ const MyApp = (function () { const CONFIG = { FORM_ID_PROP: "FORM_ID", // Script Property key for Form ID RECIPIENT: "hiring@quiles.studio", OPENAI_KEY: "OPENAI_API_KEY", // Script Property key for OpenAI API key OPENAI_URL: "https://api.openai.com/v1/chat/completions", MODEL: "gpt-4", SYSTEM_MSG: "You are an expert HR assistant. Summarize applicant info professionally." }; /** * Retrieve the Form ID from Script Properties */ function getFormId() { const formId = PropertiesService .getScriptProperties() .getProperty(CONFIG.FORM_ID_PROP); if (!formId) throw new Error(`Missing property: ${CONFIG.FORM_ID_PROP}`); return formId; } /** * Build a flat text block of Q/A pairs for summarization */ function buildRawText(map) { return Object.entries(map) .map(([q, a]) => `• ${q}: ${a}`) .join("\n\n"); } /** * Generate a JSON-formatted summary via OpenAI */ function generateSummary(rawText) { const prompt = `\n${CONFIG.SYSTEM_MSG}\n\nPlease read the applicant details below and produce a bullet-point summary under these headings:\n\nPersonal Info \nCertifications \nWork History \nBackground & Skills \nProjects & Portfolio \nOnline Presence \n\nUse 1–3 bullets per section. Output valid JSON only:\n{\n \"Personal Info\": [...],\n \"Certifications\": [...],\n \"Work History\": [...],\n \"Background & Skills\": [...],\n \"Projects & Portfolio\": [...],\n \"Online Presence\": [...]\n}\n\nApplicant details:\n${rawText}\n`; const apiKey = PropertiesService .getScriptProperties() .getProperty(CONFIG.OPENAI_KEY); if (!apiKey) throw new Error(`Missing property: ${CONFIG.OPENAI_KEY}`); const response = UrlFetchApp.fetch(CONFIG.OPENAI_URL, { method: "post", contentType: "application/json", headers: { Authorization: `Bearer ${apiKey}` }, payload: JSON.stringify({ model: CONFIG.MODEL, messages: [ { role: "system", content: CONFIG.SYSTEM_MSG }, { role: "user", content: prompt } ], temperature: 0.2 }) }); const data = JSON.parse(response.getContentText()); return data.choices?.[0]?.message?.content.trim() || "{}"; } /** * Transform a FormResponse into a Q->A map */ function buildMapping(response) { const map = {}; response.getItemResponses().forEach(ir => { let ans = ir.getResponse(); if (Array.isArray(ans)) ans = ans.join(", "); map[ir.getItem().getTitle().trim()] = ans; }); return map; } /** * Create a Google Doc containing the summary and full Q/A */ function createDoc(name, jsonSummary, mapping) { const doc = DocumentApp.create(`Application – ${name}`); const body = doc.getBody(); body.appendParagraph("📝 Structured Applicant Summary") .setHeading(DocumentApp.ParagraphHeading.HEADING1); body.appendParagraph(jsonSummary) .setFontFamily("Courier New") .setSpacingAfter(20); body.appendParagraph("📋 Full Question & Answer") .setHeading(DocumentApp.ParagraphHeading.HEADING2); Object.entries(mapping).forEach(([q,a]) => { body.appendParagraph(q).setBold(true); body.appendParagraph(a).setIndentStart(18); body.appendParagraph(""); }); doc.saveAndClose(); return doc.getId(); } /** * Process a single FormResponse: summarize, PDF, and email */ function processResponse(response) { const mapping = buildMapping(response); const name = mapping["Please enter your full name "] || "Unknown"; const rawText = buildRawText(mapping); const summary = generateSummary(rawText); const docId = createDoc(name, summary, mapping); // Convert to PDF and email const pdfBlob = DriveApp.getFileById(docId) .getAs(MimeType.PDF) .setName(`App_${name.replace(/\s+/g, "_")}.pdf`); const dateStr = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy"); GmailApp.sendEmail( CONFIG.RECIPIENT, `New Application – ${name} (${dateStr})`, "Please find attached the structured summary.", { attachments: [pdfBlob] } ); // Clean up DriveApp.getFileById(docId).setTrashed(true); } // Expose public methods return { processResponse, getFormId }; })(); /** * Form Submit trigger: runs on each new submission */ function onFormSubmit(e) { if (e?.response) { MyApp.processResponse(e.response); } else { Logger.log("onFormSubmit: no response data"); } } /** * Test Mode: process only the most recent submission */ function testLastSubmission() { try { const formId = MyApp.getFormId(); const form = FormApp.openById(formId); const responses = form.getResponses(); if (!responses.length) { Logger.log("testLastSubmission: no form responses."); return; } MyApp.processResponse(responses.pop()); } catch (err) { Logger.log(`testLastSubmission error: ${err}`); } } /** * Manual Mode: process ALL existing submissions */ function runAllSubmissions() { try { const formId = MyApp.getFormId(); const form = FormApp.openById(formId); const responses = form.getResponses(); if (!responses.length) { Logger.log("runAllSubmissions: no form responses."); return; } responses.forEach(r => MyApp.processResponse(r)); } catch (err) { Logger.log(`runAllSubmissions error: ${err}`); } }

Certainly! Here's a well-structured PDF template for a job application report. This template includes sections for applicant information, technical skills, work experience, and interview notes in a professional format.

Updated files
v1