diff --git a/server/.env.example b/server/.env.example index 99b569c..cb94d86 100644 --- a/server/.env.example +++ b/server/.env.example @@ -29,6 +29,9 @@ LLM_API_KEY= LLM_MODEL= LLM_TEMPERATURE=0 LLM_TIMEOUT_SECONDS=180 +# Optional override of the consolidation system prompt. If unset or empty, a default is used. +# Single line — escape newlines with \n if your shell preserves them, or put the prompt on one logical line. +LLM_SYSTEM_PROMPT="Du bist ein medizinischer Assistent. Fasse die folgenden diktierten Abschnitte zu einem zusammenhängenden Text zusammen. Bereinigen und strukturieren, nichts hinzufügen, nichts interpretieren, keine Diagnose, keine Arztbrief-Struktur. Entferne Redundanzen. Spätere Aufnahmen haben Vorrang — Korrekturen, Nachträge und Widersprüche zugunsten der chronologisch letzten Aussage auflösen. Antworte auf Deutsch. Nur der zusammengefasste Text, keine Einleitung, kein Abschlusssatz." # Session SESSION_TIMEOUT_HOURS=8 diff --git a/server/src/analyze/worker.rs b/server/src/analyze/worker.rs index 2f9b784..202c532 100644 --- a/server/src/analyze/worker.rs +++ b/server/src/analyze/worker.rs @@ -80,7 +80,7 @@ async fn process( let document = match llm::chat_once( client, &settings, - prompt::SYSTEM_PROMPT, + &config.llm_system_prompt, &user_content, timeout, ) diff --git a/server/src/config.rs b/server/src/config.rs index bb317cc..2c1041e 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -53,6 +53,11 @@ pub struct Config { pub llm_model: String, pub llm_temperature: f32, pub llm_timeout_seconds: u64, + /// System prompt sent to the analysis LLM. Defaults to + /// `crate::analyze::prompt::SYSTEM_PROMPT` if `LLM_SYSTEM_PROMPT` is unset + /// or empty. Runtime-configurable so admins can iterate and use the + /// "Neu analysieren" button to re-run cases. + pub llm_system_prompt: String, pub session_timeout_hours: u32, /// Whether to set the `Secure` flag on the session cookie. Default `true`. /// Set `COOKIE_SECURE=false` only for plain-HTTP local development — @@ -87,6 +92,14 @@ impl Config { llm_model: optional_env("LLM_MODEL", ""), llm_temperature: optional_env_parsed("LLM_TEMPERATURE", 0.0), llm_timeout_seconds: optional_env_parsed("LLM_TIMEOUT_SECONDS", 180), + llm_system_prompt: { + let v = optional_env("LLM_SYSTEM_PROMPT", ""); + if v.is_empty() { + crate::analyze::prompt::SYSTEM_PROMPT.to_string() + } else { + v + } + }, session_timeout_hours: optional_env_parsed("SESSION_TIMEOUT_HOURS", 8), cookie_secure: optional_env_parsed("COOKIE_SECURE", true), } @@ -135,6 +148,7 @@ impl Config { llm_model: String::new(), llm_temperature: 0.0, llm_timeout_seconds: 180, + llm_system_prompt: crate::analyze::prompt::SYSTEM_PROMPT.to_string(), session_timeout_hours: 8, cookie_secure: false, } diff --git a/server/src/main.rs b/server/src/main.rs index 2a5ab08..fc166ba 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -48,6 +48,17 @@ async fn main() { ); } + { + let custom = std::env::var("LLM_SYSTEM_PROMPT") + .map(|v| !v.is_empty()) + .unwrap_or(false); + info!( + prompt_source = if custom { "env" } else { "default" }, + prompt_chars = config.llm_system_prompt.chars().count(), + "system prompt loaded" + ); + } + // Shared HTTP client for both downstream pipelines. let http_client = reqwest::Client::builder() .build()