diff --git a/packages/summarizer/summarizer.ts b/packages/summarizer/summarizer.ts index 2bc2d3e..354c7c5 100644 --- a/packages/summarizer/summarizer.ts +++ b/packages/summarizer/summarizer.ts @@ -916,6 +916,28 @@ function buildScoringFallbackBegruendung( return `${farbe} (${meaning}). Staerkste Bereiche: ${strongestDimensions || "keine"}.${missing}`; } +function fallbackScoringAssessment(reason: string): Partial & { begruendung?: string } { + return { + begruendung: `Die automatische Detailbewertung konnte nicht vollstaendig ausgewertet werden: ${reason}`, + ausschlussgruende: [], + dimensionen: SCORING_MODEL.map((dimension) => ({ + id: dimension.id, + subcriteria: dimension.subcriteria.map((subcriterion) => ({ + id: subcriterion.id, + farbe: "unbewertbar", + evidence: "", + begruendung: "", + confidence: 0, + missingReason: `Modellantwort konnte nach ${MAX_LLM_RETRY_ATTEMPTS} Versuchen nicht als gueltiges JSON gelesen werden.`, + })), + })), + }; +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + async function assessTrafficLight( client: OpenAI, model: string, @@ -932,12 +954,7 @@ async function assessTrafficLight( scoringModel: SCORING_MODEL, }; - const parsed = await createParsedStructuredCompletion & { - begruendung?: string; - }>( - client, - model, - [ + const messages: Array<{ role: "system" | "user"; content: string }> = [ { role: "system", content: @@ -971,7 +988,15 @@ Wichtige Vorgaben: Bewerbungsdaten: ${JSON.stringify(data, null, 2)}`, }, - ], + ]; + let parsed: Partial & { begruendung?: string }; + try { + parsed = await createParsedStructuredCompletion & { + begruendung?: string; + }>( + client, + model, + messages, "ampelbewertung", { type: "object", @@ -1015,7 +1040,10 @@ ${JSON.stringify(data, null, 2)}`, "Could not parse traffic light assessment JSON", sessionId, { operation: "scoring", label: "Ampelbewertung", onLlmCall }, - ); + ); + } catch (error) { + parsed = fallbackScoringAssessment(errorMessage(error)); + } const ausschlussgruende = Array.isArray(parsed.ausschlussgruende) ? parsed.ausschlussgruende.map((flag) => String(flag).trim()).filter(Boolean) : []; @@ -1049,10 +1077,7 @@ async function segmentMultiQuestionAnswer( return fragen; } - const parsed = await createParsedStructuredCompletion<{ fragen?: Array> }>( - client, - model, - [ + const messages: Array<{ role: "system" | "user"; content: string }> = [ { role: "system", content: @@ -1081,7 +1106,13 @@ Vorgaben: - Mehrfachnennungen sind erlaubt, wenn ein Abschnitt mehrere Unterfragen klar beantwortet. - Lasse keine Unterfrage aus.`, }, - ], + ]; + let parsed: { fragen?: Array> }; + try { + parsed = await createParsedStructuredCompletion<{ fragen?: Array> }>( + client, + model, + messages, "segmentierung_unterfragen", { type: "object", @@ -1107,7 +1138,17 @@ Vorgaben: `Could not parse answer segmentation JSON for ${fallbackLabel}`, sessionId, { operation: "segmentierung", label: fallbackLabel, onLlmCall }, - ); + ); + } catch { + parsed = { + fragen: fragen.map((frage) => ({ + id: frage.id, + text: frage.text, + antwort: "", + confidence: 0, + })), + }; + } const byId = new Map((parsed.fragen ?? []).map((frage) => [String(frage.id ?? ""), frage])); return fragen.map((frage) => { @@ -1139,10 +1180,7 @@ async function analyzeSWOT( sessionId?: string, onLlmCall?: SummarizeCompanyOptions["onLlmCall"], ): Promise { - const parsed = await createParsedStructuredCompletion>( - client, - model, - [ + const messages: Array<{ role: "system" | "user"; content: string }> = [ { role: "system", content: @@ -1165,7 +1203,13 @@ Vorgaben: Bewerbungsdaten: ${JSON.stringify(data, null, 2)}`, }, - ], + ]; + let parsed: Partial; + try { + parsed = await createParsedStructuredCompletion>( + client, + model, + messages, "swot_analyse", { type: "object", @@ -1181,7 +1225,15 @@ ${JSON.stringify(data, null, 2)}`, "Could not parse SWOT analysis JSON", sessionId, { operation: "swot", label: "SWOT-Analyse", onLlmCall }, - ); + ); + } catch (error) { + parsed = { + staerken: [], + schwaechen: [], + chancen: [], + risiken: [`SWOT-Analyse konnte nicht automatisch erstellt werden: ${errorMessage(error)}`], + }; + } const toStringArray = (value: unknown): string[] => Array.isArray(value) ? value.map((item) => String(item).trim()).filter(Boolean) : [];