KI-Chat: Thread-Titel vom Modell formulieren lassen
Der Titel in der Seitenleiste waren bisher die ersten 60 Zeichen der
ersten Nachricht - abgeschnitten mitten im Wort ("Ich habe mich bei der
Hetzner Online GmbH bewor..."). Jetzt formuliert das Modell daraus einen
kurzen Titel, wie man es aus ChatGPT kennt.
- Der Aufruf laeuft NACH dem done-Event: die Antwort wartet nicht auf die
Titelgenerierung (1-3 s), der Titel kommt als eigenes Event nach und die
Seitenleiste zieht live nach.
- Der abgeschnittene Titel bleibt als Platzhalter, solange die Antwort
streamt - die Seitenleiste ist also nie leer, und faellt die
Titelgenerierung aus, bleibt es schlicht dabei.
- Nur beim ersten Schlagabtausch und nur, wenn der Thread noch keinen
Titel hatte: ein selbst vergebener Name wird nicht ueberschrieben.
- Eigener Mini-Systemprompt statt des Chat-Prompts, der will beraten,
nicht betiteln. Anfuehrungszeichen/"Titel:"-Praefixe werden abgeraeumt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+40
-1
@@ -180,6 +180,45 @@ async function runChat({ system, messages, tools, executeTool, onToken, onToolCa
|
||||
throw new Error('Maximale Anzahl Tool-Aufrufe erreicht.');
|
||||
}
|
||||
|
||||
// Kurzen Thread-Titel aus dem ersten Schlagabtausch formulieren lassen — wie in
|
||||
// ChatGPT, statt die ersten 60 Zeichen der Frage abzuschneiden ("Ich habe mich
|
||||
// bei der Hetzner Online GmbH bewor…"). Ein eigener, winziger Aufruf ohne
|
||||
// Werkzeuge: Der Chat-Systemprompt würde hier nur stören (er will beraten, nicht
|
||||
// betiteln). Wirft nicht — schlägt die Titelgenerierung fehl, bleibt der Aufrufer
|
||||
// einfach beim Fallback-Titel.
|
||||
async function generateTitle({ userText, assistantText, signal }) {
|
||||
const system =
|
||||
'Du formulierst kurze Titel für Chat-Verläufe eines Bewerbungs-Assistenten. ' +
|
||||
'Antworte mit NICHTS außer dem Titel: 2 bis 5 Wörter, Deutsch, keine ' +
|
||||
'Anführungszeichen, kein Punkt am Ende, keine Einleitung. Benenne das Thema ' +
|
||||
'konkret (Firma, Stelle oder Anliegen), nicht generisch wie "Frage zur Bewerbung".';
|
||||
const inhalt =
|
||||
'Nachricht des Nutzers:\n' + String(userText || '').slice(0, 600) +
|
||||
'\n\nAntwort des Assistenten:\n' + String(assistantText || '').slice(0, 600) +
|
||||
'\n\nTitel:';
|
||||
|
||||
try {
|
||||
const { content } = await streamChat({
|
||||
system,
|
||||
messages: [{ role: 'user', content: inhalt }],
|
||||
temperature: 0.2,
|
||||
signal,
|
||||
});
|
||||
// Modelle packen den Titel gern in Anführungszeichen, Sternchen oder eine
|
||||
// "Titel:"-Zeile — das wieder abräumen.
|
||||
let titel = String(content || '')
|
||||
.split('\n').map((z) => z.trim()).filter(Boolean).pop() || '';
|
||||
titel = titel
|
||||
.replace(/^\s*(titel|title)\s*:\s*/i, '')
|
||||
.replace(/^["“„'*#\s]+|["“”'*.\s]+$/g, '')
|
||||
.trim();
|
||||
if (titel.length > 60) titel = titel.slice(0, 60).trim();
|
||||
return titel;
|
||||
} catch (err) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// Build the German system prompt that grounds the assistant. `context` is the
|
||||
// lightweight core gathered by the server: { heute, settings, profil }.
|
||||
// Application data is NOT baked in — the assistant fetches it via tools.
|
||||
@@ -231,7 +270,7 @@ function buildContextPrompt(ctx) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isConfigured, streamChat, runChat, buildContextPrompt, MAX_TOOL_ROUNDS,
|
||||
isConfigured, streamChat, runChat, buildContextPrompt, generateTitle, MAX_TOOL_ROUNDS,
|
||||
// Dynamic so an edit on /einstellungen is reflected without a restart.
|
||||
get OLLAMA_MODEL() { return config.ollama().model; },
|
||||
};
|
||||
Reference in New Issue
Block a user