stt-cli 0.2.1

Speech to text Cli using Groq API and OpenAI API
use anyhow::{Context, Result};
use std::fs;
use std::path::Path;
use std::sync::Once;
use tracing::{debug, error, info, instrument, Level};
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

static INIT: Once = Once::new();

#[derive(Clone, Debug)]
pub struct TracingConfig {
    pub debug_mode: bool,
    pub data_dir: String,
}

impl Default for TracingConfig {
    fn default() -> Self {
        Self {
            debug_mode: std::env::var("DEBUG").is_ok(),
            data_dir: "data_dir".to_string(),
        }
    }
}

pub fn initialize(config: TracingConfig) -> Result<()> {
    let mut result = Ok(());

    INIT.call_once(|| {
        result = setup_tracing(&config);

        // Create data directory
        if let Err(e) = fs::create_dir_all(&config.data_dir) {
            error!("Failed to create data directory: {}", e);
            result = Err(anyhow::anyhow!("Failed to create data directory: {}", e));
        }
    });

    result
}

fn setup_tracing(config: &TracingConfig) -> Result<()> {
    // Create logs directory
    let logs_dir = Path::new("logs");
    fs::create_dir_all(logs_dir)?;

    // Set up file appender for logs
    let file_appender = RollingFileAppender::new(Rotation::DAILY, logs_dir, "application.log");

    let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);

    // Determine the default level based on debug mode
    let default_level = if config.debug_mode {
        Level::DEBUG
    } else {
        Level::INFO
    };

    // Create and register subscriber with environment filter
    let env_filter = EnvFilter::try_from_default_env()
        .unwrap_or_else(|_| EnvFilter::new(format!("{}", default_level)));

    tracing_subscriber::registry()
        .with(
            fmt::Layer::default()
                .with_writer(std::io::stdout)
                .with_ansi(true),
        )
        .with(
            fmt::Layer::default()
                .with_writer(non_blocking)
                .with_ansi(false),
        )
        .with(env_filter)
        .init();

    info!("Tracing initialized with debug_mode: {}", config.debug_mode);

    // Keep _guard in a static to prevent it from being dropped
    // This ensures the non-blocking writer continues to work
    static mut GUARD: Option<tracing_appender::non_blocking::WorkerGuard> = None;
    unsafe {
        GUARD = Some(_guard);
    }

    Ok(())
}

#[instrument(skip(audio_data))]
pub fn save_audio_chunk(chunk_id: u64, audio_data: &[u8], data_dir: &str) -> Result<()> {
    let debug_mode = std::env::var("DEBUG").is_ok();
    if !debug_mode {
        return Ok(());
    }

    let chunk_path = Path::new(data_dir).join(format!("chunk_{}.wav", chunk_id));
    debug!("Saving audio chunk to {:?}", chunk_path);

    fs::write(&chunk_path, audio_data)
        .with_context(|| format!("Failed to save audio chunk to {:?}", chunk_path))?;

    info!("Saved audio chunk: {:?}", chunk_path);
    Ok(())
}

pub fn is_debug_mode() -> bool {
    std::env::var("DEBUG").is_ok()
}