Skip to content
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
f299da2
fix(ci-analytics): parallelize API requests with Promise.all to preve…
pisum-sativum Jul 21, 2026
5a9ecf1
feat: Automatically sort SOCIALS list alphabetically
pisum-sativum Jul 22, 2026
e6f1ded
Merge remote-tracking branch 'origin/main' into fix-socials-sort
pisum-sativum Jul 22, 2026
6978cd3
fix: resolve TS2322 type error in SOCIALS sort by casting array as So…
pisum-sativum Jul 22, 2026
dff1d44
fix: resolve GraphQL request deduplication and sanitize PAT errors (#…
pisum-sativum Jul 22, 2026
4d4e10f
fix: resolve garbage characters extraction in resume parser
pisum-sativum Jul 22, 2026
aaa38b7
fix(resume-parser): propagate buffer.toString errors instead of swall…
pisum-sativum Jul 22, 2026
9dace07
chore: revert unrelated changes from PR
pisum-sativum Jul 23, 2026
8172a7f
fix(BurnoutRiskTable): add missing Image import to fix TS2322 and pre…
pisum-sativum Jul 23, 2026
126c4da
Merge remote-tracking branch 'origin/main' into fix-resume-parser-gar…
pisum-sativum Jul 23, 2026
32f1c03
style: fix prettier formatting in BurnoutRiskTable, InteractiveViewer…
pisum-sativum Jul 23, 2026
6b41c1d
style: fix UTF-8 encoding and prettier formatting; restore unrelated …
pisum-sativum Jul 23, 2026
5e844ac
style: restore InteractiveViewer and achievements to origin/main exac…
pisum-sativum Jul 23, 2026
2e2730a
style: fix prettier formatting for remaining files
pisum-sativum Jul 23, 2026
aff9f34
revert: revert all unrelated file changes so PR only targets lib/resu…
pisum-sativum Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions lib/resume-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,45 +136,58 @@ async function extractTextFromBuffer(buffer: Buffer, mimeType: string): Promise<
let rawText = '';

if (mimeType === 'application/pdf') {
try {
if (buffer.toString('utf-8', 0, 4) === '%PDF') {
const header = buffer.toString('utf-8', 0, 4);
if (header === '%PDF') {
try {
const { PDFParse } = await import('pdf-parse');

const parser = new PDFParse({ data: buffer });
const result = await parser.getText();
await parser.destroy();

rawText = result.text;
} else {
rawText = buffer.toString('utf-8');
} catch (error) {
console.warn('Failed to parse PDF using pdf-parse:', error);
rawText = '';
}
} catch (error) {
console.warn('Failed to parse PDF using pdf-parse, falling back to UTF-8 decoding:', error);
} else {
rawText = buffer.toString('utf-8');
}
} else if (
mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
) {
try {
if (buffer.toString('utf-8', 0, 2) === 'PK') {
const header = buffer.toString('utf-8', 0, 2);
if (header === 'PK') {
try {
const mammothModule = await import('mammoth');
const mammothParser = ((mammothModule as unknown as { default?: unknown }).default ||
mammothModule) as typeof mammothModule;
const result = await mammothParser.extractRawText({ buffer });
rawText = result.value;
} else {
rawText = buffer.toString('utf-8');
} catch (error) {
console.warn('Failed to parse DOCX using mammoth:', error);
rawText = '';
}
} catch (error) {
console.warn('Failed to parse DOCX using mammoth, falling back to UTF-8 decoding:', error);
} else {
rawText = buffer.toString('utf-8');
}
} else {
rawText = buffer.toString('utf-8');
}

try {
if (rawText.includes('Ã')) {
const fixedText = Buffer.from(rawText, 'latin1').toString('utf-8');
if (!fixedText.includes('\uFFFD')) {
rawText = fixedText;
}
}
} catch (e) {
// Ignore encoding fix errors
}

const printable = rawText
.replace(/[^\x20-\x7E\n\r]/g, ' ')
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFFFD]/g, '')
.replace(/[ \t]+/g, ' ')
.replace(/\r/g, '')
.trim();
Expand Down
Loading