fix(llm): LLM antwortet jetzt in der konfigurierten Systemsprache

Bisher wurde `language` zwar an STT/TTS übergeben, aber nie an den LLM.
Lokales Modell antwortete deshalb immer auf Englisch/Deutsch, egal ob
Französisch, Spanisch o.a. eingestellt war.

Lösung: `language`-Parameter durch die gesamte LLM-Schicht gezogen:
- base.py: `lang_instruction()` helper + Signatur erweitert
- local_openai_compatible.py: Sprachanweisung ("Respond in Français.")
  wird als letzter System-Part in den Message-Stack eingefügt
- openrouter.py: Explizite Sprachanweisung ergänzt den bestehenden
  "Answer in the same language as the user"-Prompt
- fallback.py: FallbackLLMProvider leitet `language` durch
- orchestrator.py: alle 3 LLM-Aufrufstellen übergeben `language`
- Tests: alle Stub-LLMs um `language=None` ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-19 14:12:16 +02:00
commit 81d4cf6fd8
14 changed files with 89 additions and 44 deletions

View file

@ -2,7 +2,7 @@ from collections.abc import AsyncIterator
import httpx
from app.providers.llm.base import LLMProvider, sse_delta
from app.providers.llm.base import LLMProvider, lang_instruction, sse_delta
SYSTEM_PROMPT = """
@ -51,7 +51,9 @@ class OpenRouterLLMProvider(LLMProvider):
self.api_key = (api_key or "").strip()
self.model = (model or "").strip()
def _build_messages(self, text: str, history: list[dict] | None) -> list[dict]:
def _build_messages(
self, text: str, history: list[dict] | None, language: str | None = None
) -> list[dict]:
if not self.api_key:
raise ValueError("OPENROUTER_API_KEY is empty")
if not self.model:
@ -59,7 +61,12 @@ class OpenRouterLLMProvider(LLMProvider):
if not text or not text.strip():
raise ValueError("LLM input text is empty")
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
system_content = SYSTEM_PROMPT
instr = lang_instruction(language)
if instr:
system_content = f"{SYSTEM_PROMPT}\n\n{instr}"
messages = [{"role": "system", "content": system_content}]
if history:
messages.extend(history)
messages.append({"role": "user", "content": text.strip()})
@ -70,10 +77,11 @@ class OpenRouterLLMProvider(LLMProvider):
text: str,
history: list[dict] | None = None,
session_id: str | None = None,
language: str | None = None,
) -> str:
payload = {
"model": self.model,
"messages": self._build_messages(text, history),
"messages": self._build_messages(text, history, language=language),
}
timeout = httpx.Timeout(connect=10.0, read=120.0, write=30.0, pool=10.0)
@ -115,10 +123,11 @@ class OpenRouterLLMProvider(LLMProvider):
text: str,
history: list[dict] | None = None,
session_id: str | None = None,
language: str | None = None,
) -> AsyncIterator[str]:
payload = {
"model": self.model,
"messages": self._build_messages(text, history),
"messages": self._build_messages(text, history, language=language),
"stream": True,
}
timeout = httpx.Timeout(connect=10.0, read=120.0, write=30.0, pool=10.0)