Skip to main content

speechmarkdown_rust/formatters/
base.rs

1use crate::ast::AstNode;
2use crate::error::Result;
3use std::collections::HashMap;
4
5/// Supported TTS platforms
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub enum Platform {
8    AmazonAlexa,
9    GoogleAssistant,
10    MicrosoftAzure,
11    Apple,
12    W3c,
13    SamsungBixby,
14    ElevenLabs,
15    IbmWatson,
16}
17
18impl Platform {
19    /// Parse platform from string
20    pub fn from_platform_str(s: &str) -> Option<Self> {
21        match s.to_lowercase().as_str() {
22            "amazon-alexa" | "alexa" => Some(Platform::AmazonAlexa),
23            "google-assistant" | "google" => Some(Platform::GoogleAssistant),
24            "microsoft-azure" | "azure" => Some(Platform::MicrosoftAzure),
25            "apple" => Some(Platform::Apple),
26            "w3c" => Some(Platform::W3c),
27            "samsung-bixby" | "bixby" => Some(Platform::SamsungBixby),
28            "elevenlabs" => Some(Platform::ElevenLabs),
29            "ibm-watson" | "watson" => Some(Platform::IbmWatson),
30            _ => None,
31        }
32    }
33
34    /// Convert platform to string identifier
35    pub fn as_str(&self) -> &'static str {
36        match self {
37            Platform::AmazonAlexa => "amazon-alexa",
38            Platform::GoogleAssistant => "google-assistant",
39            Platform::MicrosoftAzure => "microsoft-azure",
40            Platform::Apple => "apple",
41            Platform::W3c => "w3c",
42            Platform::SamsungBixby => "samsung-bixby",
43            Platform::ElevenLabs => "elevenlabs",
44            Platform::IbmWatson => "ibm-watson",
45        }
46    }
47}
48
49/// Voice mapping for custom voice names
50#[derive(Debug, Clone)]
51pub struct VoiceMapping {
52    pub voice_attributes: HashMap<String, String>,
53}
54
55/// Options for formatters
56#[derive(Debug, Clone)]
57pub struct FormatterOptions {
58    pub platform: Platform,
59    pub include_speak_tag: bool,
60    pub include_paragraph_tag: bool,
61    pub preserve_empty_lines: bool,
62    pub escape_xml_symbols: bool,
63    pub include_formatter_comment: bool,
64    pub voices: Option<HashMap<String, VoiceMapping>>,
65}
66
67impl Default for FormatterOptions {
68    fn default() -> Self {
69        Self {
70            platform: Platform::AmazonAlexa,
71            include_speak_tag: true,
72            include_paragraph_tag: false,
73            preserve_empty_lines: true,
74            escape_xml_symbols: false,
75            include_formatter_comment: false,
76            voices: None,
77        }
78    }
79}
80
81/// Base trait for all formatters
82pub trait Formatter {
83    /// Format an AST into a string
84    fn format(&self, ast: &AstNode) -> Result<String>;
85
86    /// Format a single node
87    fn format_node(&self, node: &AstNode) -> Result<String>;
88}
89
90/// Create a formatter for the specified platform
91pub fn create_formatter(platform: Platform, options: FormatterOptions) -> Box<dyn Formatter> {
92    match platform {
93        Platform::AmazonAlexa => Box::new(super::ssml::AmazonAlexaSsmlFormatter::new(options)),
94        Platform::GoogleAssistant => {
95            Box::new(super::ssml::GoogleAssistantSsmlFormatter::new(options))
96        }
97        Platform::MicrosoftAzure => {
98            Box::new(super::ssml::MicrosoftAzureSsmlFormatter::new(options))
99        }
100        Platform::Apple => {
101            // For now, use the base SSML formatter
102            Box::new(super::ssml::SsmlFormatterBase::new(options))
103        }
104        Platform::W3c => {
105            // Use the base SSML formatter for W3C standard
106            Box::new(super::ssml::SsmlFormatterBase::new(options))
107        }
108        _ => Box::new(super::TextFormatter::new()),
109    }
110}