Spaces:
Running
Running
Download src/services/pdfService.js from hari7775/resume-server: direct link, hf CLI and curl.
- Browser
- Download file 3.8 kB
-
https://huggingface.co/spaces/hari7775/resume-server/resolve/main/src/services/pdfService.js
- Command line
-
hf download hf://spaces/hari7775/resume-server/src/services/pdfService.js
-
curl -L -o pdfService.js https://huggingface.co/spaces/hari7775/resume-server/resolve/main/src/services/pdfService.js
3.8 kB
| import { renderJakeTemplate } from '../../templateRenderer.js'; | |
| import { DOWNLOAD_CLEANUP_DELAY_MS } from '../config.js'; | |
| import { BadRequestError, ForbiddenError, NotFoundError } from '../exception/errors.js'; | |
| import { createJob, getJob, deleteJob, getJobPosition } from './jobStore.js'; | |
| import { generateContentHash, getCachedPdf } from './pdfCache.js'; | |
| import { queue, enqueueRenderJob } from './jobRunner.js'; | |
| import { recordPdfGeneration } from './usageService.js'; | |
| // A cached PDF is still a generation the user received, so it is counted too. | |
| async function createCachedJob({ uid, metadata, usageDate }, cachedPdf) { | |
| await recordPdfGeneration(uid, usageDate); | |
| return createJob({ | |
| userId: uid, | |
| status: 'completed', | |
| metadata, | |
| result: cachedPdf.buffer, | |
| fromCache: true | |
| }); | |
| } | |
| // Submit a job from ready-made HTML | |
| export async function submitHtmlJob({ uid, html, metadata, usageDate }) { | |
| if (!html) throw new BadRequestError('HTML content is required'); | |
| const cacheKey = generateContentHash(html, metadata); | |
| // RAM cache hit: instant PDF retrieval (0ms render time) | |
| const cachedPdf = getCachedPdf(cacheKey); | |
| if (cachedPdf) { | |
| const job = await createCachedJob({ uid, metadata, usageDate }, cachedPdf); | |
| console.log(`[RAM Cache Hit] Served cached PDF instantly for job ${job.id} (user: ${uid})`); | |
| return { jobId: job.id, position: 0, cached: true }; | |
| } | |
| const job = createJob({ userId: uid, status: 'queued', metadata, cacheKey, usageDate }); | |
| // If all workers are occupied, position is queue backlog (queue.size + 1) | |
| const initialPosition = queue.pending >= queue.concurrency ? (queue.size + 1) : 0; | |
| enqueueRenderJob(job, html, 'Job'); | |
| const position = initialPosition > 0 ? initialPosition : getJobPosition(job.id); | |
| return { jobId: job.id, position, queueSize: queue.size, pending: queue.pending }; | |
| } | |
| // Submit a job from resume JSON, rendered server-side with the template renderer | |
| export async function submitResumeJsonJob({ uid, data, metadata, usageDate }) { | |
| if (!data) throw new BadRequestError('Resume data is required'); | |
| const cacheKey = generateContentHash(JSON.stringify(data), metadata); | |
| const jobMetadata = { ...metadata, filename: metadata?.filename || data.personal?.fullName || 'resume' }; | |
| const cachedPdf = getCachedPdf(cacheKey); | |
| if (cachedPdf) { | |
| const job = await createCachedJob({ uid, metadata: jobMetadata, usageDate }, cachedPdf); | |
| console.log(`[RAM Cache Hit] Served cached JSON PDF instantly for job ${job.id} (user: ${uid})`); | |
| return { jobId: job.id, position: 0, cached: true }; | |
| } | |
| const html = renderJakeTemplate(data); | |
| const job = createJob({ userId: uid, status: 'queued', metadata: jobMetadata, cacheKey, usageDate }); | |
| enqueueRenderJob(job, html, 'JSON Job'); | |
| return { jobId: job.id, position: getJobPosition(job.id) }; | |
| } | |
| export function getJobStatus(jobId) { | |
| const job = getJob(jobId); | |
| if (!job) throw new NotFoundError('Job not found'); | |
| return { | |
| status: job.status, | |
| position: getJobPosition(job.id), | |
| error: job.error | |
| }; | |
| } | |
| // Returns the finished PDF for its owner and schedules the job's cleanup | |
| export function takePdfForDownload(jobId, uid) { | |
| const job = getJob(jobId); | |
| if (!job || job.status !== 'completed') throw new NotFoundError('PDF not ready or job not found'); | |
| // Ensure the authenticated requester owns this job | |
| if (job.userId && job.userId !== uid) { | |
| throw new ForbiddenError('You do not have permission to download this PDF.'); | |
| } | |
| setTimeout(() => deleteJob(job.id), DOWNLOAD_CLEANUP_DELAY_MS); | |
| return { buffer: job.result, filename: job.metadata?.filename || 'resume' }; | |
| } | |