Refactor: Remove unused Whisper variants

This commit removes the `whisper_variant` and `whisper_hotwords_variant`
fields from the `run_id` generation and the `print_meta_summary`
function.

These variants are no longer used as the project is shifting focus to
LLM-based generation. The `run_full_case.rs` example has also been
updated to reflect this change.
This commit is contained in:
2026-04-30 16:56:12 +02:00
parent 6b7a1cea49
commit bb584b6ea0
18 changed files with 639 additions and 215 deletions
+1 -6
View File
@@ -54,18 +54,13 @@ fn print_meta_summary(run: &Path) -> Result<()> {
}
};
let v: serde_json::Value = serde_json::from_str(&raw).context("parsing meta.json")?;
let w = v.get("whisper_variant").and_then(|x| x.as_str()).unwrap_or("?");
let h = v
.get("whisper_hotwords_variant")
.and_then(|x| x.as_str())
.unwrap_or("none");
let l = v.get("llm_variant").and_then(|x| x.as_str()).unwrap_or("?");
let model = v.get("llm_model").and_then(|x| x.as_str()).unwrap_or("?");
let wallclock = v
.pointer("/timings_ms/wallclock_ms")
.and_then(|x| x.as_u64())
.unwrap_or(0);
println!(" whisper={w} hotwords={h} llm={l} model={model} wallclock={wallclock}ms");
println!(" llm={l} model={model} wallclock={wallclock}ms");
Ok(())
}
+23 -48
View File
@@ -6,14 +6,12 @@
//! Usage:
//! run_full_case \
//! --case-dir case_c414cf52 \
//! --whisper-prompt prompts/whisper/v1_dosing_minimal.txt \
//! --whisper-hotwords prompts/whisper_hotwords/v1_drugs.txt \
//! --llm-prompt prompts/llm/baseline.txt \
//! --runs 3
//!
//! Path conventions:
//! - `--case-dir` is relative to the experiments/ working directory
//! - `--*-prompt` and `--*-hotwords` are paths relative to `--case-dir`
//! - `--llm-prompt` is a path relative to `--case-dir`
//! - `--settings` defaults to `../server/settings.toml`
//! - `--vocab-dir` defaults to `../server/vocab`
@@ -28,7 +26,6 @@ use doctate_experiments::{
use doctate_server::analyze::llm::{self as srv_llm, LlmSettings as LlmCallSettings};
use doctate_server::analyze::prompt::render_prompt;
use doctate_server::analyze::{AnalysisInput, RecordingInput};
use doctate_server::config::WhisperUserSettings;
use doctate_server::gazetteer::{Gazetteer, SpellbookDict};
use doctate_server::settings::Settings;
use doctate_server::transcribe::ffmpeg::remux_faststart;
@@ -42,17 +39,6 @@ struct Args {
#[arg(long)]
case_dir: PathBuf,
/// Path to a Whisper `initial_prompt` file. Empty file → no
/// initial_prompt forwarded. Prompts are fall-übergreifend, typically
/// under `prompts/whisper/`.
#[arg(long)]
whisper_prompt: PathBuf,
/// Optional Whisper `hotwords` file (handle with care — see
/// `prompts/whisper_hotwords/README.md`).
#[arg(long)]
whisper_hotwords: Option<PathBuf>,
/// Path to the LLM system prompt file. Typically under `prompts/llm/`.
#[arg(long)]
llm_prompt: PathBuf,
@@ -99,19 +85,8 @@ async fn main() -> Result<()> {
);
}
let whisper_prompt_text = load_prompt(&args.whisper_prompt)?;
let whisper_hotwords_text = match args.whisper_hotwords.as_ref() {
Some(p) => Some(load_prompt(p)?),
None => None,
};
let llm_system_prompt = load_prompt(&args.llm_prompt)?;
let user_whisper = WhisperUserSettings {
language: Some("de".to_string()),
hotwords: whisper_hotwords_text.clone().filter(|s| !s.is_empty()),
initial_prompt: Some(whisper_prompt_text.clone()).filter(|s| !s.is_empty()),
};
let (gazetteer, dict_mode) = load_gazetteer(&args.vocab_dir, &args.hunspell_stem).await?;
info!(
vocab_dir = %args.vocab_dir.display(),
@@ -129,14 +104,12 @@ async fn main() -> Result<()> {
.build()
.context("building reqwest client")?;
let whisper_variant_id = stem(&args.whisper_prompt);
let hotwords_variant_id = args.whisper_hotwords.as_ref().map(stem);
let llm_variant_id = stem(&args.llm_prompt);
let runs_root = data_runs_root(&case_dir)?;
for run_index in 1..=args.runs {
let id = run_id(&whisper_variant_id, &llm_variant_id, run_index);
let id = run_id(&llm_variant_id, run_index);
let run_dir = runs_root.join(&id);
std::fs::create_dir_all(run_dir.join("transcripts"))?;
@@ -149,21 +122,18 @@ async fn main() -> Result<()> {
for audio in &audios {
let recorded_at = stem(audio);
let t_whisper = Instant::now();
let raw = transcribe_one(
&http,
&settings,
&user_whisper,
audio,
)
.await
.with_context(|| format!("transcribing {}", audio.display()))?;
let raw = transcribe_one(&http, &settings, Some("de"), audio)
.await
.with_context(|| format!("transcribing {}", audio.display()))?;
timings.whisper_total_ms += t_whisper.elapsed().as_millis() as u64;
let t_gaz = Instant::now();
let cleaned = gazetteer.replace(&raw);
timings.gazetteer_total_ms += t_gaz.elapsed().as_millis() as u64;
let transcript_path = run_dir.join("transcripts").join(format!("{recorded_at}.txt"));
let transcript_path = run_dir
.join("transcripts")
.join(format!("{recorded_at}.txt"));
atomic_write(&transcript_path, &cleaned)?;
recordings_meta.push(RecordingMeta {
@@ -191,7 +161,8 @@ async fn main() -> Result<()> {
if !args.no_llm {
let t_llm = Instant::now();
let document_raw = call_llm(&http, &settings, &llm_system_prompt, &user_content).await?;
let document_raw =
call_llm(&http, &settings, &llm_system_prompt, &user_content).await?;
timings.llm_ms = t_llm.elapsed().as_millis() as u64;
// Post-LLM gazetteer pass — mirrors `server/src/analyze/worker.rs:150`.
// Catches LLM-drift back to non-canonical forms (e.g. anglicization)
@@ -212,8 +183,6 @@ async fn main() -> Result<()> {
.file_name()
.map(|s| s.to_string_lossy().into_owned())
.unwrap_or_default(),
whisper_variant: whisper_variant_id.clone(),
whisper_hotwords_variant: hotwords_variant_id.clone(),
llm_variant: llm_variant_id.clone(),
whisper_url: settings.whisper.url.clone(),
llm_url: settings.llm.url.clone(),
@@ -280,9 +249,9 @@ async fn load_gazetteer(
fn dict_mode_clone(m: &GazetteerDictMode) -> GazetteerDictMode {
match m {
GazetteerDictMode::NoDict => GazetteerDictMode::NoDict,
GazetteerDictMode::SpellbookHunspell { stem } => GazetteerDictMode::SpellbookHunspell {
stem: stem.clone(),
},
GazetteerDictMode::SpellbookHunspell { stem } => {
GazetteerDictMode::SpellbookHunspell { stem: stem.clone() }
}
}
}
@@ -325,16 +294,22 @@ fn stem<P: AsRef<Path>>(p: P) -> String {
async fn transcribe_one(
http: &reqwest::Client,
settings: &Settings,
user_whisper: &WhisperUserSettings,
language: Option<&str>,
audio: &Path,
) -> Result<String> {
let remuxed = remux_faststart(audio)
.await
.with_context(|| format!("ffmpeg remux failed for {}", audio.display()))?;
let timeout = Duration::from_secs(settings.whisper.timeout_seconds);
let text = srv_whisper::transcribe(http, &settings.whisper.url, remuxed.path(), timeout, user_whisper)
.await
.map_err(|e| anyhow::anyhow!("whisper transcribe failed: {e}"))?;
let text = srv_whisper::transcribe(
http,
&settings.whisper.url,
remuxed.path(),
timeout,
language,
)
.await
.map_err(|e| anyhow::anyhow!("whisper transcribe failed: {e}"))?;
Ok(text)
}
+1 -3
View File
@@ -119,7 +119,7 @@ async fn main() -> Result<()> {
let runs_root = data_runs_root(&case_dir)?;
for run_index in 1..=args.runs {
let id = run_id("none", &llm_variant_id, run_index);
let id = run_id(&llm_variant_id, run_index);
let run_dir = runs_root.join(&id);
std::fs::create_dir_all(&run_dir)?;
@@ -147,8 +147,6 @@ async fn main() -> Result<()> {
.file_name()
.map(|s| s.to_string_lossy().into_owned())
.unwrap_or_default(),
whisper_variant: "none".into(),
whisper_hotwords_variant: None,
llm_variant: llm_variant_id.clone(),
whisper_url: String::new(),
llm_url: settings.llm.url.clone(),
+6 -6
View File
@@ -17,13 +17,15 @@ use time::OffsetDateTime;
use time::format_description::well_known::Iso8601;
/// Generate a run identifier in the form
/// `<UTC-ISO>_w-<wid>_l-<lid>_run<n>`. Used as the directory name under
/// `<UTC-ISO>_l-<lid>_run<n>`. Used as the directory name under
/// `case_<id>/runs/`.
pub fn run_id(whisper_variant: &str, llm_variant: &str, run_index: u32) -> String {
pub fn run_id(llm_variant: &str, run_index: u32) -> String {
let now = OffsetDateTime::now_utc();
let stamp = now.format(&Iso8601::DEFAULT).unwrap_or_else(|_| "unknown".into());
let stamp = now
.format(&Iso8601::DEFAULT)
.unwrap_or_else(|_| "unknown".into());
let safe_stamp = stamp.replace(':', "-").replace('.', "-");
format!("{safe_stamp}_w-{whisper_variant}_l-{llm_variant}_run{run_index}")
format!("{safe_stamp}_l-{llm_variant}_run{run_index}")
}
/// Read a prompt file. Returns empty string for an empty file (used as
@@ -61,8 +63,6 @@ pub struct RunMeta {
pub run_id: String,
pub created_at_utc: String,
pub case: String,
pub whisper_variant: String,
pub whisper_hotwords_variant: Option<String>,
pub llm_variant: String,
pub whisper_url: String,
pub llm_url: String,