Quellcode des ICON CRM (3)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
/*
|
||||
* Text aus einem Lebenslauf holen.
|
||||
*
|
||||
* Unterstuetzt PDF, DOCX und reinen Text. Das alte .doc-Format (Word 97) bleibt
|
||||
* aussen vor: es braeuchte einen eigenen Parser, und wer eine solche Datei hat,
|
||||
* speichert sie in Sekunden als PDF.
|
||||
*
|
||||
* pdf-parse wird ueber den internen Pfad geladen. Der Paket-Einstieg fuehrt
|
||||
* beim Import eine Selbstprobe aus und sucht dafuer eine Testdatei, die im
|
||||
* npm-Paket nicht mitgeliefert wird - das laesst den Start scheitern.
|
||||
*/
|
||||
const pdfParse = require('pdf-parse/lib/pdf-parse.js');
|
||||
|
||||
/** Mehr Text braucht kein Modell, um einen Lebenslauf zu verstehen. */
|
||||
const MAX_CHARS = 60_000;
|
||||
|
||||
export function isSupported(filename, mime = '') {
|
||||
const ext = path.extname(filename).toLowerCase();
|
||||
return (
|
||||
['.pdf', '.docx', '.txt', '.md'].includes(ext) ||
|
||||
mime === 'application/pdf' ||
|
||||
mime === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
|
||||
mime.startsWith('text/')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest die Datei und gibt ihren Text zurueck.
|
||||
*
|
||||
* @param {string} filePath absoluter Pfad
|
||||
* @param {string} originalName fuer die Endung
|
||||
*/
|
||||
export async function extractText(filePath, originalName) {
|
||||
const ext = path.extname(originalName || filePath).toLowerCase();
|
||||
|
||||
if (ext === '.pdf') {
|
||||
const result = await pdfParse(await fs.readFile(filePath));
|
||||
return clean(result.text);
|
||||
}
|
||||
|
||||
if (ext === '.docx') {
|
||||
// mammoth liefert den Fliesstext ohne Formatierung - genau das, was das
|
||||
// Modell braucht.
|
||||
const mammoth = require('mammoth');
|
||||
const result = await mammoth.extractRawText({ path: filePath });
|
||||
return clean(result.value);
|
||||
}
|
||||
|
||||
if (ext === '.txt' || ext === '.md') {
|
||||
return clean(await fs.readFile(filePath, 'utf8'));
|
||||
}
|
||||
|
||||
throw Object.assign(new Error('Dateityp wird nicht unterstützt (PDF, DOCX oder Text).'), {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Aufraeumen: PDF-Auszuege enthalten viele harte Zeilenumbrueche und
|
||||
* Mehrfachleerzeichen aus dem Satzspiegel. Das kostet nur Token und erschwert
|
||||
* dem Modell das Lesen.
|
||||
*/
|
||||
function clean(text) {
|
||||
const result = String(text ?? '')
|
||||
.replace(/\r/g, '')
|
||||
.replace(/[ \t]+/g, ' ')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim();
|
||||
|
||||
if (result.length <= MAX_CHARS) return result;
|
||||
|
||||
// Anfang und Ende behalten: vorn stehen Name und Kontaktdaten, hinten oft
|
||||
// Ausbildung und Zertifikate.
|
||||
const head = result.slice(0, Math.floor(MAX_CHARS * 0.7));
|
||||
const tail = result.slice(-Math.floor(MAX_CHARS * 0.3));
|
||||
return `${head}\n\n[… gekürzt …]\n\n${tail}`;
|
||||
}
|
||||
Reference in New Issue
Block a user