use anyhow::{Context, Result};
use serde::Deserialize;
use std::{
fs,
path::{Path, PathBuf},
};
const DEFAULT_CONFIG_PATH: &str = "vtt.config.json";
const DEFAULT_CHUNK_DURATION_SECS: usize = 5;
const DEFAULT_MODEL: &str = "whisper-1";
const DEFAULT_ENDPOINT: &str = "https://api.openai.com/v1/audio/transcriptions";
#[derive(Debug, Deserialize, Clone)]
#[serde(default)]
pub struct Config {
pub chunk_duration_secs: usize,
pub model: String,
pub endpoint: String,
pub out_file: Option<PathBuf>,
}
impl Default for Config {
fn default() -> Self {
Self {
chunk_duration_secs: DEFAULT_CHUNK_DURATION_SECS,
model: DEFAULT_MODEL.to_string(),
endpoint: DEFAULT_ENDPOINT.to_string(),
out_file: None,
}
}
}
impl Config {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
let contents = fs::read_to_string(path)
.with_context(|| format!("reading config from {}", path.display()))?;
serde_json::from_str(&contents)
.with_context(|| format!("parsing config from {}", path.display()))
}
pub fn load_or_default() -> Result<(Self, Option<PathBuf>)> {
let default_path = PathBuf::from(DEFAULT_CONFIG_PATH);
if default_path.exists() {
let config = Self::from_file(&default_path)?;
Ok((config, Some(default_path)))
} else {
Ok((Self::default(), None))
}
}
pub fn resolve_out_path(&self, source: Option<&Path>) -> Option<PathBuf> {
self.out_file.as_ref().map(|path| {
if path.is_absolute() {
path.clone()
} else if let Some(source) = source {
source
.parent()
.map(Path::to_path_buf)
.unwrap_or_else(|| PathBuf::from("."))
.join(path)
} else {
path.clone()
}
})
}
}