#![doc = include_str!("../README.md")]

use crate::asr::{AutomaticSpeechRecognition, AutomaticSpeechRecognitionConfig};
use crate::error::*;
use crate::input::{AudioInput, AudioInputConfig};
use crate::vad::{VoiceActivityDetection, VoiceActivityDetectionConfig};
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast::Receiver;

pub mod asr;
pub mod error;
pub mod input;
pub mod utils;
pub mod vad;

/// 助手项目中实时语音输入项目配置
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct NihilityListenerConfig {
    pub audio_input: AudioInputConfig,
    pub vad: VoiceActivityDetectionConfig,
    pub asr: AutomaticSpeechRecognitionConfig,
}

/// 助手项目中实时语音输入
pub struct NihilityListener {
    input: AudioInput,
    vad: VoiceActivityDetection,
    asr: AutomaticSpeechRecognition,
}

impl NihilityListener {
    /// 读取文件配置初始化语音输入实例
    pub fn init_from_file_config() -> Result<Self> {
        Self::init(nihility_config::get_config::<NihilityListenerConfig>(
            env!("CARGO_PKG_NAME"),
        )?)
    }

    /// 根据配置初始化语音输入实例
    pub fn init(config: NihilityListenerConfig) -> Result<Self> {
        let input = AudioInput::init(config.audio_input.clone())?;
        let vad = VoiceActivityDetection::init(config.vad.clone(), input.get_sample_receiver())?;
        let asr = AutomaticSpeechRecognition::init(config.asr.clone(), vad.get_speech_receiver())?;
        Ok(Self { input, vad, asr })
    }

    /// 获取音频输入采样管道接收者
    pub fn get_sample_receiver(&self) -> Receiver<f32> {
        self.input.get_sample_receiver()
    }

    /// 获取语音活动检测概率管道接收者
    pub fn get_probability_receiver(&self) -> Result<Receiver<f32>> {
        self.vad.get_probability_receiver()
    }

    /// 获取活动语音数据管道接收者
    pub fn get_speech_receiver(&self) -> Receiver<Vec<f32>> {
        self.vad.get_speech_receiver()
    }

    /// 获取自动语音识别结果管道接收者
    pub fn get_text_receiver(&self) -> Receiver<String> {
        self.asr.get_text_receiver()
    }

    /// 开始实时语音识别
    pub async fn run(&mut self) -> Result<()> {
        tokio::try_join!(self.asr.run(), self.vad.run(), self.input.run())?;
        Ok(())
    }
}
