From 5ec04984c927da77a25bc348dc5a75c69fa22432 Mon Sep 17 00:00:00 2001 From: Gulum Date: Sat, 6 Jun 2026 10:29:38 +0200 Subject: [PATCH] FEAT-14c: Charakterbogen im Sale-Ad-Prompt - Traits+Notiz als bevorzugte Charakterquelle (Notizen-Fallback), Webe-Regel statt Stichwortliste im Systemprompt; 4 Tests --- GerbilManager.Tests/SaleAdTests.cs | 57 +++++++++++++++++++ .../SaleAd/SaleAdPromptBuilder.cs | 13 ++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/GerbilManager.Tests/SaleAdTests.cs b/GerbilManager.Tests/SaleAdTests.cs index 0032df1..2134915 100644 --- a/GerbilManager.Tests/SaleAdTests.cs +++ b/GerbilManager.Tests/SaleAdTests.cs @@ -73,6 +73,63 @@ namespace GerbilManager.Tests Assert.Contains("Großer und kleiner Bruder Dynamik", prompt); } + // ── FEAT-14c: Charakterbogen (Traits + Notiz) im Prompt ──────────── + + [Fact] + public void UserPrompt_enthält_Traits_und_Charakternotiz() + { + var request = new SaleAdRequest( + [new SaleAdAnimal("Balu", "CP-Agouti", "2024-03-12", "alte Verwaltungsnotiz", + Traits: ["zutraulich", "buddelt gern"], + CharacterNote: "klettert abends auf die Hand")], + "FREI", ""); + var prompt = SaleAdPromptBuilder.BuildUserPrompt(request); + + Assert.Contains("Charakter: zutraulich, buddelt gern", prompt); + Assert.Contains("Charakter-Notiz: klettert abends auf die Hand", prompt); + } + + [Fact] + public void UserPrompt_bevorzugt_Charakterbogen_vor_generischen_Notizen() + { + // Traits vorhanden -> die generische Notiz (oft Verwaltungs-Info) + // gehört NICHT in den Prompt. + var request = new SaleAdRequest( + [new SaleAdAnimal("Balu", null, null, "Käfig wurde am 3.5. gereinigt", + Traits: ["neugierig"])], + "FREI", ""); + var prompt = SaleAdPromptBuilder.BuildUserPrompt(request); + + Assert.Contains("Charakter: neugierig", prompt); + Assert.DoesNotContain("Notizen:", prompt); + Assert.DoesNotContain("Käfig wurde", prompt); + } + + [Fact] + public void UserPrompt_fällt_ohne_Charakterbogen_auf_Notizen_zurück() + { + // Kein Charakterbogen (null bzw. leer) -> Notizen wie bisher. + var request = new SaleAdRequest( + [ + new SaleAdAnimal("Mysti", null, null, "sehr verschmust", Traits: null), + new SaleAdAnimal("Bo", null, null, "mag Kolbenhirse", Traits: []), + ], + "FREI", ""); + var prompt = SaleAdPromptBuilder.BuildUserPrompt(request); + + Assert.Contains("Notizen: sehr verschmust", prompt); + Assert.Contains("Notizen: mag Kolbenhirse", prompt); + Assert.DoesNotContain("Charakter:", prompt); + } + + [Fact] + public void SystemPrompt_verlangt_fließende_Prosa_statt_Stichwortliste() + { + var prompt = SaleAdPromptBuilder.BuildSystemPrompt(); + Assert.Contains("Charakter-Eigenschaften", prompt); + Assert.Contains("niemals als Aufzählung", prompt); + } + [Theory] [InlineData("2024-03-12", "12.03.2024")] [InlineData("kaputt", "kaputt")] // unparsebar -> unverändert durchreichen diff --git a/GerbilManagerWebAPI/SaleAd/SaleAdPromptBuilder.cs b/GerbilManagerWebAPI/SaleAd/SaleAdPromptBuilder.cs index 757d7b3..73f75b9 100644 --- a/GerbilManagerWebAPI/SaleAd/SaleAdPromptBuilder.cs +++ b/GerbilManagerWebAPI/SaleAd/SaleAdPromptBuilder.cs @@ -58,7 +58,8 @@ namespace GerbilManagerWebAPI.SaleAd Harte Regeln: - NIEMALS Preise oder Schutzgebühren nennen. - - KEINE Fakten erfinden: Verwende ausschließlich die mitgelieferten Daten (Namen, Farbschläge, Geburtsdaten, Notizen). Fehlt eine Angabe, lässt du sie weg. + - KEINE Fakten erfinden: Verwende ausschließlich die mitgelieferten Daten (Namen, Farbschläge, Geburtsdaten, Charakter-Angaben, Notizen). Fehlt eine Angabe, lässt du sie weg. + - Charakter-Eigenschaften (Stichworte wie „zutraulich“, „buddelt gern“) und die Charakter-Notiz sind die Grundlage der Persönlichkeits-Prosa: Verwebe sie zu FLIESSENDEM Text — niemals als Aufzählung oder Stichwortliste ausgeben. - Sprache: Deutsch, warm und liebevoll, aber nicht kitschig-übertrieben. - Gib NUR den Inserat-Text aus — keine Erklärungen, keine Markdown-Code-Blöcke. @@ -85,12 +86,18 @@ namespace GerbilManagerWebAPI.SaleAd sb.Append($" | Farbschlag: {animal.Farbschlag}"); if (!string.IsNullOrWhiteSpace(animal.DateOfBirth)) sb.Append($" | geboren am {FormatGermanDate(animal.DateOfBirth)}"); - if (!string.IsNullOrWhiteSpace(animal.Notes)) - sb.Append($" | Notizen: {animal.Notes}"); + // FEAT-14c: Charakterbogen (Traits + Notiz) ist die BEVORZUGTE + // Charakterquelle; die generischen Notizen dienen nur als + // Fallback, wenn kein Charakterbogen gepflegt ist (sie enthalten + // oft Verwaltungs-Infos, die nicht ins Inserat gehören). + var hasCharacter = animal.Traits is { Count: > 0 } + || !string.IsNullOrWhiteSpace(animal.CharacterNote); if (animal.Traits is { Count: > 0 }) sb.Append($" | Charakter: {string.Join(", ", animal.Traits)}"); if (!string.IsNullOrWhiteSpace(animal.CharacterNote)) sb.Append($" | Charakter-Notiz: {animal.CharacterNote}"); + if (!hasCharacter && !string.IsNullOrWhiteSpace(animal.Notes)) + sb.Append($" | Notizen: {animal.Notes}"); sb.AppendLine(); } if (!string.IsNullOrWhiteSpace(request.Hints))