feat: Add gazetteer annotation to user prompt
This commit introduces functionality to annotate the user prompt with potential proper name corrections from a gazetteer. The LLM will then use these annotations to improve the accuracy of transcriptions, especially for medical terms and names. The `SYSTEM_PROMPT` has also been updated to inform the LLM about these new annotations and how to handle them.
This commit is contained in:
@@ -2,7 +2,7 @@ use super::AnalysisInput;
|
||||
|
||||
/// System prompt for the consolidation LLM. From docs/projektplan.md:365-369.
|
||||
/// Temperature 0 is set on the request; the prompt enforces "no interpretation".
|
||||
pub const SYSTEM_PROMPT: &str = "Du bist ein medizinischer Assistent. Fasse die folgenden diktierten Abschnitte zu einem zusammenhängenden Text zusammen. Bereinigen und strukturieren, nichts hinzufügen, keine medizinische Interpretation, 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.\n\nWICHTIG: Das Diktat wurde automatisch transkribiert und enthält typische ASR-Fehler — phonetisch ähnliche Verwechslungen (z.B. \"Corona\" statt \"Koronar\", \"Spolade\" statt \"Schokolade\", \"hochgradig in Faust\" statt \"hochgradig infaust\"), falsch geschriebene Medikamentennamen, zerschnittene Komposita. Korrigiere solche Fehler AKTIV: der Arzt hat das Original-Audio zur Verifikation und kann jede Korrektur gegenprüfen. Bei sicherer Korrektur: schreibe das korrigierte Wort. Bei Unsicherheit, wie die Korrektur lauten müsste: behalte das Original bei.\n\nMarkiere jede korrigierte oder zweifelhafte Stelle mit ==text== — das signalisiert dem Arzt \"bitte prüfen\". Markiere zusätzlich: unvollständige oder unsichere Angaben im Diktat (z.B. \"Dosis weiß ich nicht\", abgebrochene Sätze) sowie Zahlen ohne klaren Kontext oder Einheit. Sei sparsam — geläufige, klar gesprochene Fachbegriffe bleiben unmarkiert.";
|
||||
pub const SYSTEM_PROMPT: &str = "Du bist ein medizinischer Assistent. Fasse die folgenden diktierten Abschnitte zu einem zusammenhängenden Text zusammen. Bereinigen und strukturieren, nichts hinzufügen, keine medizinische Interpretation, 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.\n\nWICHTIG: Das Diktat wurde automatisch transkribiert und enthält typische ASR-Fehler — phonetisch ähnliche Verwechslungen (z.B. \"Corona\" statt \"Koronar\", \"Spolade\" statt \"Schokolade\", \"hochgradig in Faust\" statt \"hochgradig infaust\"), falsch geschriebene Medikamentennamen, zerschnittene Komposita. Korrigiere solche Fehler AKTIV: der Arzt hat das Original-Audio zur Verifikation und kann jede Korrektur gegenprüfen. Bei sicherer Korrektur: schreibe das korrigierte Wort. Bei Unsicherheit, wie die Korrektur lauten müsste: behalte das Original bei.\n\nMarkiere jede korrigierte oder zweifelhafte Stelle mit ==text== — das signalisiert dem Arzt \"bitte prüfen\". Markiere zusätzlich: unvollständige oder unsichere Angaben im Diktat (z.B. \"Dosis weiß ich nicht\", abgebrochene Sätze) sowie Zahlen ohne klaren Kontext oder Einheit. Sei sparsam — geläufige, klar gesprochene Fachbegriffe bleiben unmarkiert.\n\nDer Text kann Hinweise der Form `Wort [?Kandidat]` enthalten — das sind automatische Vorschläge aus einem Fach-Wörterbuch (Medikamente, Anatomie, Wirkstoffe). Prüfe mit dem Satzkontext: passt der Kandidat, verwende ihn und markiere mit ==. Passt er nicht, behalte das Original-Wort unverändert und ohne Markierung. Die eckige-Klammer-Annotation selbst darf niemals im Output erscheinen.";
|
||||
|
||||
/// Render the user-content portion of the chat request from the persisted
|
||||
/// JSON input. Recordings with blank text are skipped — they carry no signal
|
||||
|
||||
@@ -13,25 +13,22 @@ use crate::{BusyGuard, WorkerBusy};
|
||||
/// Consume analyze jobs sequentially. The external LLM tolerates parallelism,
|
||||
/// but sequential processing keeps the architecture simple and shields the
|
||||
/// provider from bursts. Trivial to lift later via `tokio::spawn(process(..))`.
|
||||
///
|
||||
/// `_vocab` is the gazetteer for proper-name correction. Currently unused;
|
||||
/// wired into `process()` in a follow-up step.
|
||||
pub async fn run(
|
||||
mut rx: AnalyzeReceiver,
|
||||
config: Arc<Config>,
|
||||
client: reqwest::Client,
|
||||
worker_busy: WorkerBusy,
|
||||
_vocab: Arc<Gazetteer>,
|
||||
vocab: Arc<Gazetteer>,
|
||||
) {
|
||||
info!(
|
||||
vocab_entries = _vocab.len(),
|
||||
vocab_entries = vocab.len(),
|
||||
"Analyze worker started"
|
||||
);
|
||||
let timeout = Duration::from_secs(config.llm_timeout_seconds);
|
||||
|
||||
while let Some(job) = rx.recv().await {
|
||||
let _guard = BusyGuard::new(worker_busy.clone());
|
||||
process(&job.case_dir, &config, &client, timeout).await;
|
||||
process(&job.case_dir, &config, &client, &vocab, timeout).await;
|
||||
}
|
||||
|
||||
warn!("Analyze worker stopped (channel closed)");
|
||||
@@ -41,6 +38,7 @@ async fn process(
|
||||
case_dir: &Path,
|
||||
config: &Config,
|
||||
client: &reqwest::Client,
|
||||
vocab: &Gazetteer,
|
||||
timeout: Duration,
|
||||
) {
|
||||
let input_path = case_dir.join(ANALYSIS_INPUT_FILE);
|
||||
@@ -80,7 +78,12 @@ async fn process(
|
||||
return;
|
||||
}
|
||||
|
||||
// Render the raw transcript bundle, then inject gazetteer hints for
|
||||
// tokens that phonetically resemble known proper names. The LLM sees
|
||||
// annotations of the form `Token [?Candidate]` and decides in context
|
||||
// whether to adopt them.
|
||||
let user_content = prompt::render_prompt(&input);
|
||||
let user_content = vocab.annotate(&user_content);
|
||||
let total_chars = user_content.chars().count();
|
||||
info!(
|
||||
case = %case_dir.display(),
|
||||
|
||||
Reference in New Issue
Block a user