fix(analyze): drop transcript timestamp headings from LLM prompt
render_prompt prefixed each recording with a '## <recorded_at>' heading. No system prompt consumes that timestamp, and the LLM occasionally echoed it into the final document as a heading. Join recordings with the bare '\n\n---\n\n' separator instead; chronology is carried by recording order. Adds a regression test pinning that no RFC3339 timestamp or '##' reaches the prompt. closes #8
This commit is contained in:
@@ -4,6 +4,13 @@ use super::AnalysisInput;
|
|||||||
/// JSON input. Recordings with blank text are skipped — they carry no signal
|
/// JSON input. Recordings with blank text are skipped — they carry no signal
|
||||||
/// for the LLM and only add noise. Chronological order is taken as given;
|
/// for the LLM and only add noise. Chronological order is taken as given;
|
||||||
/// callers must sort `recordings` before passing in (the handler does).
|
/// callers must sort `recordings` before passing in (the handler does).
|
||||||
|
///
|
||||||
|
/// Recordings are concatenated with a `\n\n---\n\n` separator and nothing
|
||||||
|
/// else: no per-recording heading or timestamp. The `recorded_at` value is
|
||||||
|
/// deliberately omitted — no system prompt consumes it, and feeding it as a
|
||||||
|
/// Markdown heading caused the LLM to occasionally echo transcript timestamps
|
||||||
|
/// into the final document (issue #8). Chronology is carried by the order of
|
||||||
|
/// `recordings` alone.
|
||||||
pub fn render_prompt(input: &AnalysisInput) -> String {
|
pub fn render_prompt(input: &AnalysisInput) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
@@ -15,9 +22,6 @@ pub fn render_prompt(input: &AnalysisInput) -> String {
|
|||||||
out.push_str("\n\n---\n\n");
|
out.push_str("\n\n---\n\n");
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
out.push_str("## ");
|
|
||||||
out.push_str(&r.recorded_at);
|
|
||||||
out.push_str("\n\n");
|
|
||||||
out.push_str(r.text.trim());
|
out.push_str(r.text.trim());
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
@@ -48,7 +52,7 @@ mod tests {
|
|||||||
"2026-04-15T10:32:00Z",
|
"2026-04-15T10:32:00Z",
|
||||||
"Patient klagt über Knie.",
|
"Patient klagt über Knie.",
|
||||||
)]));
|
)]));
|
||||||
assert_eq!(out, "## 2026-04-15T10:32:00Z\n\nPatient klagt über Knie.");
|
assert_eq!(out, "Patient klagt über Knie.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -57,9 +61,20 @@ mod tests {
|
|||||||
("2026-04-15T10:32:00Z", "Erste Aufnahme."),
|
("2026-04-15T10:32:00Z", "Erste Aufnahme."),
|
||||||
("2026-04-15T10:38:15Z", "Zweite Aufnahme."),
|
("2026-04-15T10:38:15Z", "Zweite Aufnahme."),
|
||||||
]));
|
]));
|
||||||
assert!(out.contains("\n\n---\n\n"));
|
assert_eq!(out, "Erste Aufnahme.\n\n---\n\nZweite Aufnahme.");
|
||||||
assert!(out.starts_with("## 2026-04-15T10:32:00Z"));
|
}
|
||||||
assert!(out.contains("## 2026-04-15T10:38:15Z"));
|
|
||||||
|
/// Regression guard for issue #8: transcript timestamps must never reach
|
||||||
|
/// the LLM prompt — they leaked into the final document as headings.
|
||||||
|
#[test]
|
||||||
|
fn omits_recording_timestamps() {
|
||||||
|
let out = render_prompt(&mk(vec![
|
||||||
|
("2026-04-15T10:32:00Z", "Erste Aufnahme."),
|
||||||
|
("2026-04-15T10:38:15Z", "Zweite Aufnahme."),
|
||||||
|
]));
|
||||||
|
assert!(!out.contains("2026-04-15T10:32:00Z"));
|
||||||
|
assert!(!out.contains("2026-04-15T10:38:15Z"));
|
||||||
|
assert!(!out.contains("##"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user