[feat] add input validation, enhanced error messages, and new integration tests

This commit is contained in:
2025-08-12 09:49:11 +02:00
parent 8ebdf876ed
commit 75cfb6f160
5 changed files with 181 additions and 24 deletions

View File

@@ -694,10 +694,11 @@ pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result<Vec<f32>> {
}
};
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(anyhow!(
"ffmpeg failed for {}: {}",
"Failed to decode audio from {} using ffmpeg. This may indicate the file is not a valid or supported audio/video file, is corrupted, or cannot be opened. ffmpeg stderr: {}",
audio_path.display(),
String::from_utf8_lossy(&output.stderr)
stderr.trim()
));
}
let bytes = output.stdout;

View File

@@ -186,6 +186,22 @@ fn is_audio_file(path: &Path) -> bool {
false
}
fn validate_input_path(path: &Path) -> anyhow::Result<()> {
use anyhow::{anyhow, Context};
let display = path.display();
if !path.exists() {
return Err(anyhow!("Input not found: {}", display));
}
let md = std::fs::metadata(path).with_context(|| format!("Failed to stat input: {}", display))?;
if md.is_dir() {
return Err(anyhow!("Input is a directory (expected a file): {}", display));
}
// Attempt to open to catch permission errors early
std::fs::File::open(path)
.with_context(|| format!("Failed to open input file: {}", display))
.map(|_| ())
}
struct LastModelCleanup {
path: PathBuf,
}
@@ -315,6 +331,18 @@ fn run() -> Result<()> {
return Err(anyhow!("No input files provided"));
}
// Preflight: validate each input path and type
for inp in &inputs {
let p = Path::new(inp);
validate_input_path(p)?;
if !(is_audio_file(p) || is_json_file(p)) {
return Err(anyhow!(
"Unsupported input type (expected .json transcript or common audio/video): {}",
p.display()
));
}
}
// Language must be provided via CLI when transcribing audio (no detection from JSON/env)
let lang_hint: Option<String> = if let Some(ref l) = args.language {
normalize_lang_code(l).or_else(|| Some(l.trim().to_lowercase()))

View File

@@ -620,10 +620,13 @@ fn download_one_model(client: &Client, models_dir: &Path, entry: &ModelEntry) ->
url
);
let mut resp = client
.get(url)
.get(url.clone())
.send()
.and_then(|r| r.error_for_status())
.context("Failed to download model")?;
.with_context(|| format!(
"Failed to download model {} from {}. If your terminal has display/TTY issues, try running with --no-progress.",
entry.name, url
))?;
let tmp_path = models_dir.join(format!("ggml-{}.bin.part", entry.name));
if tmp_path.exists() {