active_call/playbook/
mod.rs

1use anyhow::{Result, anyhow};
2use serde::{Deserialize, Serialize};
3use std::{collections::HashMap, path::Path};
4use tokio::fs;
5use crate::EouOption;
6use crate::media::recorder::RecorderOption;
7use crate::media::vad::VADOption;
8use crate::synthesis::SynthesisOption;
9use crate::transcription::TranscriptionOption;
10
11#[derive(Debug, Deserialize, Serialize, Clone, Default)]
12#[serde(rename_all = "camelCase")]
13pub struct PlaybookConfig {
14    pub asr: Option<TranscriptionOption>,
15    pub tts: Option<SynthesisOption>,
16    pub llm: Option<LlmConfig>,
17    pub vad: Option<VADOption>,
18    pub denoise: Option<bool>,
19    pub recorder: Option<RecorderOption>,
20    pub extra: Option<HashMap<String, String>>,
21    pub eou: Option<EouOption>,
22}
23
24#[derive(Debug, Deserialize, Serialize, Clone, Default)]
25#[serde(rename_all = "camelCase")]
26pub struct LlmConfig {
27    pub provider: String,
28    pub model: Option<String>,
29    pub base_url: Option<String>,
30    pub api_key: Option<String>,
31    pub prompt: Option<String>,
32    pub greeting: Option<String>,
33}
34
35#[derive(Debug, Clone)]
36pub struct Playbook {
37    pub config: PlaybookConfig,
38}
39
40impl Playbook {
41    pub async fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
42        let content = fs::read_to_string(path).await?;
43        if !content.starts_with("---") {
44            return Err(anyhow!("Missing front matter"));
45        }
46
47        let parts: Vec<&str> = content.splitn(3, "---").collect();
48        if parts.len() < 3 {
49            return Err(anyhow!("Invalid front matter format"));
50        }
51
52        let yaml_str = parts[1];
53        let prompt = parts[2].trim().to_string();
54
55        let mut config: PlaybookConfig = serde_yaml::from_str(yaml_str)?;
56        if let Some(llm) = config.llm.as_mut() {
57            llm.prompt = Some(prompt);
58        }
59
60        Ok(Self { config })
61    }
62}
63
64pub mod dialogue;
65pub mod handler;
66pub mod runner;
67
68pub use dialogue::DialogueHandler;
69pub use handler::{LlmHandler, RagRetriever};
70pub use runner::PlaybookRunner;