feat: Tarife einstellbar + 15 weitere Filler + Mitteilung bei Leer-Antwort
- Strompreis (EUR/kWh), Notruf-Kosten (EUR/Alarm), Cartesia ($/Zeichen) jetzt im
Admin live einstellbar (RUNTIME_SETTABLE).
- OPENING-Beruhigungssaetze 12 -> 27 (random.choice; formale "Sie"-Uebersetzung
ersetzt beim Neustart den alten "dich"-Cache).
- Leer-/kein-Treffer-Antwort: statt Stille eine freundliche lokalisierte
Mitteilung ("Dazu konnte ich keine Informationen finden."), gesprochen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
363d0ab3c9
commit
f875e421de
3 changed files with 44 additions and 4 deletions
|
|
@ -10,6 +10,21 @@ from app.metrics import timer, metrics
|
|||
# zwischen Geduldssätzen, bei noch laufender Recherche.
|
||||
FILLER_PATIENCE_INTERVAL = 10.0
|
||||
|
||||
# Freundliche Mitteilung statt Stille, wenn keine Antwort zustande kommt
|
||||
# (z. B. Web-Suche ohne Treffer). Senior wartet sonst vergeblich. Fallback Deutsch.
|
||||
_NO_RESULT = {
|
||||
"de": "Dazu konnte ich leider keine Informationen finden.",
|
||||
"en": "I'm sorry, I couldn't find any information about that.",
|
||||
"nl": "Daarover kon ik helaas geen informatie vinden.",
|
||||
"fr": "Je suis désolé, je n'ai trouvé aucune information à ce sujet.",
|
||||
"es": "Lo siento, no he encontrado información al respecto.",
|
||||
"it": "Mi dispiace, non ho trovato informazioni in merito.",
|
||||
}
|
||||
|
||||
|
||||
def _no_result_message(language: str | None) -> str:
|
||||
return _NO_RESULT.get((language or "de").lower(), _NO_RESULT["de"])
|
||||
|
||||
|
||||
def _stage(name: str):
|
||||
return timer("stage_duration_seconds", {"stage": name})
|
||||
|
|
@ -135,8 +150,8 @@ class Orchestrator:
|
|||
history=history,
|
||||
language=effective_language,
|
||||
)
|
||||
if not trace.semantic_response:
|
||||
raise RuntimeError("LLM returned an empty response")
|
||||
if not (trace.semantic_response or "").strip():
|
||||
trace.semantic_response = _no_result_message(effective_language)
|
||||
|
||||
trace.spoken_response = await self.spoken_adapter.run(
|
||||
trace.semantic_response,
|
||||
|
|
@ -330,9 +345,16 @@ class Orchestrator:
|
|||
for sentence in chunker.feed(result):
|
||||
await _dispatch(sentence)
|
||||
|
||||
trace.semantic_response = "".join(parts)
|
||||
trace.semantic_response = "".join(parts).strip()
|
||||
if not trace.semantic_response:
|
||||
raise RuntimeError("LLM returned an empty response")
|
||||
# Keine Antwort (z. B. Suche ohne Treffer) -> freundliche Mitteilung
|
||||
# statt Stille, damit der Nutzer nicht vergeblich wartet.
|
||||
trace.semantic_response = _no_result_message(effective_language)
|
||||
if on_token:
|
||||
await on_token(trace.semantic_response)
|
||||
if chunker:
|
||||
for sentence in chunker.feed(trace.semantic_response):
|
||||
await _dispatch(sentence)
|
||||
trace.citations = collected_citations
|
||||
trace.web_searches = search_count[0]
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,21 @@ OPENING_PHRASES = [
|
|||
"Give me a second, I'll find that out for you.",
|
||||
"I'm checking that for you now, one moment please.",
|
||||
"Let me look that up so I can tell you exactly.",
|
||||
"Let me check the current details for you — it won't take long.",
|
||||
"I'll find the up-to-date answer for you, one moment.",
|
||||
"Allow me a brief moment to look into that.",
|
||||
"Let me gather the latest information for you.",
|
||||
"I'm on it — just give me a short moment.",
|
||||
"Let me make sure I have the current facts for you.",
|
||||
"One moment please, I'm fetching the latest for you.",
|
||||
"Let me quickly check what's current on that.",
|
||||
"I'll look into that for you right away, just a moment.",
|
||||
"Bear with me a second while I find that out.",
|
||||
"Let me get you the most recent information on that.",
|
||||
"Just a brief moment — I'm checking the latest for you.",
|
||||
"I'll dig that up for you now, one moment please.",
|
||||
"Let me find the current answer so I can tell you properly.",
|
||||
"Let me take a quick look and find that out for you.",
|
||||
]
|
||||
|
||||
PATIENCE_PHRASES = [
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ RUNTIME_SETTABLE: dict[str, tuple[str, str, str]] = {
|
|||
"memory_extraction_every_n_turns": ("Extraktion alle N Turns", "int", "z.B. 3"),
|
||||
"daily_request_limit": ("Tageskontingent (global)", "int", "0 = unbegrenzt"),
|
||||
"cost_daily_limit_usd": ("Kostenbudget/Tag (global, $)", "float", "0 = unbegrenzt — pro Nutzer überschreibbar"),
|
||||
"electricity_price_eur_per_kwh": ("Strompreis (€/kWh)", "float", "Kosten lokaler LLM-Anfragen (z.B. 0.33)"),
|
||||
"emergency_alert_eur": ("Notruf-Kosten (€/Alarm)", "float", "SMS+Anruf pro Alarm (z.B. 0.20)"),
|
||||
"cartesia_usd_per_char": ("Cartesia-TTS ($/Zeichen)", "float", "z.B. 0.00005 (100k Credits ≈ 100.000 Zeichen)"),
|
||||
"emergency_cooldown_minutes": ("Notruf-Sperre (Minuten)", "int", "Erneuter Alarm für N Minuten blockiert (Standard 5, 0 = aus)"),
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue