FEAT-12a: provider-agnostic sale-ad AI core - AiOptions (env-only), German prompt builder w/ few-shot, OpenAI-compatible chat-completions client (no SDK)
This commit is contained in:
107
GerbilManagerWebAPI/SaleAd/SaleAdPromptBuilder.cs
Normal file
107
GerbilManagerWebAPI/SaleAd/SaleAdPromptBuilder.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace GerbilManagerWebAPI.SaleAd
|
||||
{
|
||||
/// <summary>
|
||||
/// FEAT-12a: assembles the German prompt for the sale-ad (Abgabe-Inserat)
|
||||
/// generation. Style and rules follow the breeder's real Jimdo listings
|
||||
/// (analysed in hive/agents/god/FEAT12-jimdo-publish-research.md):
|
||||
/// group-based listings, status line, bold emotive tagline, per-animal
|
||||
/// Farbschlag + "geboren am DD.MM.YYYY" + personality prose, NO PRICES.
|
||||
/// </summary>
|
||||
public static class SaleAdPromptBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Two few-shot examples derived from the documented listing template.
|
||||
/// NOTE: the research file documents the format and one real tagline;
|
||||
/// these examples are synthesized to that template. Swap in verbatim
|
||||
/// listings from kleine-chaoten.jimdofree.com when available.
|
||||
/// </summary>
|
||||
private const string ExampleListing1 = """
|
||||
Status: FREI
|
||||
|
||||
„Großer und kleiner Bruder Dynamik“ – Männliches Rennmaus-Duo sucht ein liebevolles Zuhause
|
||||
|
||||
Balu – CP-Agouti, geboren am 12.03.2024
|
||||
Balu ist der ruhige Pol des Duos: Er beobachtet erst in aller Seelenruhe und buddelt sich dann zielstrebig durch jedes Einstreu-Projekt. Aus der Hand nimmt er Leckerlis schon ganz vorsichtig.
|
||||
|
||||
Benny – Schwarz Schecke, geboren am 12.03.2024
|
||||
Benny ist der Entdecker: kein Röhrchen bleibt unerforscht, kein Häuschen unbewohnt. Mit seinem Bruder kuschelt er sich abends ins Nest — getrennt werden die beiden deshalb nicht.
|
||||
|
||||
Die zwei werden nur gemeinsam in ein rennmausgerechtes Zuhause abgegeben.
|
||||
""";
|
||||
|
||||
private const string ExampleListing2 = """
|
||||
Status: LOCKER RESERVIERT Anna
|
||||
|
||||
„Zwei Schwestern, ein Herz und ganz viel Neugier“ – Weibliches Duo sucht seine Menschen
|
||||
|
||||
Frieda – Gold, geboren am 28.06.2024
|
||||
Frieda ist die Mutige der beiden und steht beim Öffnen des Geheges sofort am Glas. Sie liebt Kolbenhirse und nimmt sie dir behutsam aus den Fingern.
|
||||
|
||||
Fine – Agouti, geboren am 28.06.2024
|
||||
Fine ist etwas zurückhaltender, taut aber neben ihrer Schwester schnell auf. Beim abendlichen Buddeln sind die zwei ein unschlagbares Team.
|
||||
|
||||
Die Schwestern ziehen selbstverständlich nur zusammen um.
|
||||
""";
|
||||
|
||||
/// <summary>System prompt: role, style description, hard rules, few-shot examples.</summary>
|
||||
public static string BuildSystemPrompt() => $"""
|
||||
Du schreibst Abgabe-Inserate für Mongolische Rennmäuse im Stil der „Zucht der kleinen Chaoten“.
|
||||
|
||||
Stil und Aufbau (verbindlich):
|
||||
- Erste Zeile: die Status-Zeile, exakt wie vorgegeben (z. B. „Status: FREI“).
|
||||
- Danach eine fette, emotionale Überschrift (Tagline) in Anführungszeichen mit kurzem Untertitel, die den Charakter der Gruppe einfängt.
|
||||
- Danach pro Tier ein Absatz: Name – Farbschlag, geboren am TT.MM.JJJJ, gefolgt von warmherziger Persönlichkeits-Prosa auf Basis der mitgelieferten Notizen.
|
||||
- Abschluss: ein Satz, dass die Tiere nur gemeinsam in ein artgerechtes Zuhause abgegeben werden.
|
||||
|
||||
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.
|
||||
- Sprache: Deutsch, warm und liebevoll, aber nicht kitschig-übertrieben.
|
||||
- Gib NUR den Inserat-Text aus — keine Erklärungen, keine Markdown-Code-Blöcke.
|
||||
|
||||
Beispiel 1:
|
||||
{ExampleListing1}
|
||||
|
||||
Beispiel 2:
|
||||
{ExampleListing2}
|
||||
""";
|
||||
|
||||
/// <summary>User prompt: the actual group data + the user's free-text hints.</summary>
|
||||
public static string BuildUserPrompt(SaleAdRequest request)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Erstelle ein Abgabe-Inserat für folgende Gruppe:");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"Status-Zeile: {request.StatusLine}");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("Tiere:");
|
||||
foreach (var animal in request.Animals)
|
||||
{
|
||||
sb.Append($"- Name: {animal.Name}");
|
||||
if (!string.IsNullOrWhiteSpace(animal.Farbschlag))
|
||||
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}");
|
||||
sb.AppendLine();
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(request.Hints))
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"Wünsche/Hinweise: {request.Hints}");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>ISO "YYYY-MM-DD" -> "TT.MM.JJJJ"; anything else passes through verbatim.</summary>
|
||||
internal static string FormatGermanDate(string isoDate) =>
|
||||
DateOnly.TryParseExact(isoDate, "yyyy-MM-dd", CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.None, out var date)
|
||||
? date.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture)
|
||||
: isoDate;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user