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
+78 -24
View File
@@ -3,15 +3,6 @@ use std::path::PathBuf;
use serde::Deserialize;
/// Per-user Whisper transcription settings from users.toml.
/// All fields optional — missing `[user.whisper]` block yields defaults (None).
#[derive(Debug, Default, Clone, Deserialize)]
pub struct WhisperUserSettings {
pub language: Option<String>,
pub hotwords: Option<String>,
pub initial_prompt: Option<String>,
}
/// Per-user retention settings from users.toml.
///
/// `auto_close_days = 0` disables the auto-close sweep (a case is never
@@ -48,8 +39,11 @@ pub struct User {
pub api_key: String,
pub web_password: String,
pub role: String,
/// ASR input language code (e.g. "de", "en"). Forwarded as the
/// `language` form/query field to the active ASR backend
/// (Whisper or Canary). Missing field → backend default ("de").
#[serde(default)]
pub whisper: WhisperUserSettings,
pub language: Option<String>,
#[serde(default)]
pub retention: RetentionUserSettings,
/// Time window (hours) that defines which cases are visible to this
@@ -75,6 +69,31 @@ struct UsersFile {
user: Vec<User>,
}
/// Active ASR backend, picked once at server startup from the
/// `ASR_BACKEND` env var. `Whisper` (default) routes the worker to the
/// `whisper-asr-webservice` at `[whisper].url`; `Canary` routes it to
/// the NeMo Canary container at `[canary].url`. Switching backends
/// requires a server restart — both cannot run on the same GPU at
/// once (12 GB VRAM budget; see docs/canary.md §2.6).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AsrBackend {
#[default]
Whisper,
Canary,
}
impl std::str::FromStr for AsrBackend {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.trim().to_ascii_lowercase().as_str() {
"whisper" => Ok(Self::Whisper),
"canary" => Ok(Self::Canary),
other => Err(format!("expected 'whisper' or 'canary', got '{other}'")),
}
}
}
/// Bootstrap config loaded once from `.env` at startup. Runtime-tunable
/// values (retention, whisper/ollama/llm endpoints, prompts) live in
/// `Settings` (loaded from `settings.toml`).
@@ -104,6 +123,10 @@ pub struct Config {
/// Set `COOKIE_SECURE=false` only for plain-HTTP local development —
/// browsers refuse `Secure` cookies on non-HTTPS origins.
pub cookie_secure: bool,
/// Selected ASR backend (Whisper or Canary). Read from `ASR_BACKEND`
/// env var at startup; default `Whisper`. Worker uses this to dispatch
/// the transcription call to the matching endpoint.
pub asr_backend: AsrBackend,
}
impl Config {
@@ -127,6 +150,9 @@ impl Config {
)),
session_timeout_hours: optional_env_parsed("SESSION_TIMEOUT_HOURS", 8),
cookie_secure: optional_env_parsed("COOKIE_SECURE", true),
asr_backend: optional_env("ASR_BACKEND", "whisper")
.parse::<AsrBackend>()
.unwrap_or_else(|e| panic!("Invalid value for ASR_BACKEND: {e}")),
}
}
@@ -157,6 +183,7 @@ impl Config {
hunspell_dict_path: PathBuf::new(),
session_timeout_hours: 8,
cookie_secure: false,
asr_backend: AsrBackend::Whisper,
}
}
}
@@ -243,7 +270,7 @@ mod tests {
api_key: api_key.into(),
web_password: String::new(),
role: "doctor".into(),
whisper: WhisperUserSettings::default(),
language: None,
retention: RetentionUserSettings::default(),
window_hours: default_window_hours(),
preview_lines: default_preview_lines(),
@@ -251,7 +278,7 @@ mod tests {
}
#[test]
fn parses_user_without_whisper_block() {
fn parses_user_without_language() {
let toml_str = r#"
[[user]]
slug = "a"
@@ -261,9 +288,7 @@ mod tests {
"#;
let parsed: UsersFile = toml::from_str(toml_str).unwrap();
let u = &parsed.user[0];
assert!(u.whisper.language.is_none());
assert!(u.whisper.hotwords.is_none());
assert!(u.whisper.initial_prompt.is_none());
assert!(u.language.is_none());
}
#[test]
@@ -348,23 +373,17 @@ mod tests {
}
#[test]
fn parses_user_with_full_whisper_block() {
fn parses_user_with_explicit_language() {
let toml_str = r#"
[[user]]
slug = "a"
api_key = "k1"
web_password = ""
role = "doctor"
[user.whisper]
language = "de"
hotwords = "HOCM Valsalva"
initial_prompt = "Kardiologie"
language = "de"
"#;
let parsed: UsersFile = toml::from_str(toml_str).unwrap();
let w = &parsed.user[0].whisper;
assert_eq!(w.language.as_deref(), Some("de"));
assert_eq!(w.hotwords.as_deref(), Some("HOCM Valsalva"));
assert_eq!(w.initial_prompt.as_deref(), Some("Kardiologie"));
assert_eq!(parsed.user[0].language.as_deref(), Some("de"));
}
#[test]
@@ -430,4 +449,39 @@ mod tests {
let parsed: UsersFile = toml::from_str(toml_str).unwrap();
assert_eq!(parsed.user[0].window_hours, 168);
}
// ----- AsrBackend -----
#[test]
fn asr_backend_default_is_whisper() {
assert_eq!(AsrBackend::default(), AsrBackend::Whisper);
}
#[test]
fn asr_backend_parses_whisper() {
assert_eq!(
"whisper".parse::<AsrBackend>().unwrap(),
AsrBackend::Whisper
);
}
#[test]
fn asr_backend_parses_canary() {
assert_eq!("canary".parse::<AsrBackend>().unwrap(), AsrBackend::Canary);
}
#[test]
fn asr_backend_parses_case_insensitive_with_whitespace() {
assert_eq!(
" Whisper ".parse::<AsrBackend>().unwrap(),
AsrBackend::Whisper
);
assert_eq!("CANARY".parse::<AsrBackend>().unwrap(), AsrBackend::Canary);
}
#[test]
fn asr_backend_rejects_invalid() {
let err = "wav2vec".parse::<AsrBackend>().unwrap_err();
assert!(err.contains("wav2vec"), "got: {err}");
}
}