Choose enclosed attachments before generating; drop instant-generate
The generate form now lets the user pick which extra attachments (basis_anhaenge) to enclose — none selected by default. Only the chosen ones are attached, and their names are passed to the LLM so the cover letter's "Anlagen" list and wording reflect exactly what is enclosed. Job offers keep only "Als Bewerbung übernehmen" (draft first); the "Übernehmen & KI-Unterlagen" button and its route are removed. REST API: POST /applications/:id/generate accepts an optional `anlagen` array of attachment IDs (Swagger updated). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+6
-1
@@ -387,7 +387,12 @@ function createExternalApi(deps) {
|
||||
[id]
|
||||
);
|
||||
|
||||
runGeneration(id);
|
||||
// Optional: IDs of static attachments (basis_anhaenge) to enclose; none
|
||||
// by default. Also reflected in the cover letter's "Anlagen" list.
|
||||
const anlagenIds = Array.isArray((req.body || {}).anlagen)
|
||||
? req.body.anlagen.map((v) => parseInt(v, 10)).filter((n) => !Number.isNaN(n))
|
||||
: [];
|
||||
runGeneration(id, { anlagenIds });
|
||||
res.status(202).json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('API generate error:', error);
|
||||
|
||||
+14
-2
@@ -127,7 +127,7 @@ const OUTPUT_SCHEMA = {
|
||||
required: ['headline', 'kontakt', 'anschreiben', 'email', 'lebenslauf'],
|
||||
};
|
||||
|
||||
async function generateTailoredTexts({ job, basisDokumente, settings, llmNotizen = '' }) {
|
||||
async function generateTailoredTexts({ job, basisDokumente, settings, llmNotizen = '', zusatzAnlagen = [] }) {
|
||||
const apiKey = process.env.OLLAMA_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
@@ -215,11 +215,19 @@ async function generateTailoredTexts({ job, basisDokumente, settings, llmNotizen
|
||||
`${llmNotizen.trim()}\n\n`
|
||||
: '';
|
||||
|
||||
// Attachments actually enclosed with this application. The Lebenslauf is
|
||||
// always part of the set; the extra items are the ones the user selected.
|
||||
const anlagenListe = ['Lebenslauf', ...(zusatzAnlagen || []).filter(Boolean)];
|
||||
const anlagenText =
|
||||
`# Beigefügte Anlagen (genau diese Dokumente liegen der Bewerbung bei)\n` +
|
||||
anlagenListe.map((a) => `- ${a}`).join('\n') + `\n\n`;
|
||||
|
||||
const userPrompt =
|
||||
`# Bewerberdaten\n${bewerber}\n\n` +
|
||||
`# Basis-Unterlagen des Bewerbers (Faktengrundlage — NUR diese Fakten verwenden)\n${basisText}\n\n` +
|
||||
`# Zielstelle\n${stelleText}\n\n` +
|
||||
notizenText +
|
||||
anlagenText +
|
||||
`# Aufgabe\n` +
|
||||
`Erzeuge die TEXTE für ein Anschreiben und einen Lebenslauf, passgenau auf diese ` +
|
||||
`Stelle zugeschnitten. Layout/Design ist bereits vorgegeben — liefere nur die Inhalte. ` +
|
||||
@@ -257,6 +265,10 @@ async function generateTailoredTexts({ job, basisDokumente, settings, llmNotizen
|
||||
`Nenne den AKTUELLEN Arbeitgeber NIE beim Namen im Anschreiben (keine Firmenbezeichnung wie z. B. ` +
|
||||
`"IT-Problemlöser GmbH") — beschreibe höchstens die Tätigkeit/Rolle allgemein, falls überhaupt relevant. ` +
|
||||
`Der Lebenslauf nennt die Arbeitgeber wie gehabt; diese Regel gilt nur für das Anschreiben. ` +
|
||||
`Berücksichtige die beigefügten Anlagen (siehe Abschnitt "Beigefügte Anlagen"): Du darfst im Text ` +
|
||||
`natürlich auf relevante Anlagen verweisen (z. B. "wie meine beigefügten Arbeitszeugnisse zeigen"), ` +
|
||||
`aber erfinde KEINE Anlagen, die dort nicht aufgeführt sind, und stütze keine Aussage auf einen Nachweis, ` +
|
||||
`der nicht beiliegt. Erstelle KEINE eigene "Anlagen:"-Auflistung im Text — die Anlagenliste wird separat erzeugt. ` +
|
||||
`Nur der ERSTE Absatz beginnt mit einem KLEINbuchstaben (die Anrede endet mit Komma, der Satz wird ` +
|
||||
`fortgesetzt), z. B. "mit …" oder "als …" — außer das erste Wort ist ein Substantiv, ein Eigenname oder die ` +
|
||||
`Höflichkeitsform "Ihre/Ihr/Ihnen". Alle WEITEREN Absätze sind neue Sätze und beginnen normal mit GROSSbuchstaben.\n` +
|
||||
@@ -1129,7 +1141,7 @@ function hasLebenslauf(l) {
|
||||
}
|
||||
|
||||
async function generateApplicationDocuments({ job, basisDokumente, settings, zusatzAnlagen = [], llmNotizen = '', signatur = null, bewerbungsfoto = null }) {
|
||||
const data = await generateTailoredTexts({ job, basisDokumente, settings, llmNotizen });
|
||||
const data = await generateTailoredTexts({ job, basisDokumente, settings, llmNotizen, zusatzAnlagen });
|
||||
const headline = data.headline || job.stelle || '';
|
||||
const header = buildHeader(settings, data.kontakt, headline);
|
||||
|
||||
|
||||
@@ -346,6 +346,13 @@ function buildOpenApiSpec(baseUrl = '') {
|
||||
type: 'object',
|
||||
properties: {
|
||||
llm_notizen: { type: 'string', description: 'Freitext-Kontext für die KI (optional)' },
|
||||
anlagen: {
|
||||
type: 'array',
|
||||
items: { type: 'integer' },
|
||||
description:
|
||||
'IDs der zusätzlich beizulegenden statischen Anlagen (basis_anhaenge). ' +
|
||||
'Standard: keine. Die Auswahl erscheint auch im Anschreiben unter "Anlagen".',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user