use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::agent::AwsCredentials;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AwsPollySpeakProvider {
pub voice: AwsPollyVoice,
pub language: String,
#[deprecated(
since = "0.12.0",
note = "Use the `language` field instead. Mirrors deprecation in the AsyncAPI spec."
)]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub language_code: Option<String>,
pub engine: AwsPollyEngine,
pub credentials: AwsCredentials,
}
#[allow(deprecated)]
impl AwsPollySpeakProvider {
pub fn new(
voice: AwsPollyVoice,
language: impl Into<String>,
engine: AwsPollyEngine,
credentials: AwsCredentials,
) -> Self {
Self {
voice,
language: language.into(),
language_code: None,
engine,
credentials,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum AwsPollyVoice {
Matthew,
Joanna,
Amy,
Emma,
Brian,
Arthur,
Aria,
Ayanda,
Other(String),
}
impl AwsPollyVoice {
pub fn as_str(&self) -> &str {
match self {
Self::Matthew => "Matthew",
Self::Joanna => "Joanna",
Self::Amy => "Amy",
Self::Emma => "Emma",
Self::Brian => "Brian",
Self::Arthur => "Arthur",
Self::Aria => "Aria",
Self::Ayanda => "Ayanda",
Self::Other(s) => s,
}
}
}
impl From<String> for AwsPollyVoice {
fn from(value: String) -> Self {
match value.as_str() {
"Matthew" => Self::Matthew,
"Joanna" => Self::Joanna,
"Amy" => Self::Amy,
"Emma" => Self::Emma,
"Brian" => Self::Brian,
"Arthur" => Self::Arthur,
"Aria" => Self::Aria,
"Ayanda" => Self::Ayanda,
_ => Self::Other(value),
}
}
}
impl Serialize for AwsPollyVoice {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for AwsPollyVoice {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
Ok(Self::from(String::deserialize(de)?))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum AwsPollyEngine {
Generative,
LongForm,
Standard,
Neural,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::agent::AwsCredentialsType;
use serde_json::json;
#[test]
fn round_trip_iam_credentials() {
let raw = json!({
"voice": "Joanna",
"language": "en-US",
"engine": "neural",
"credentials": {
"type": "iam",
"region": "us-east-1",
"access_key_id": "AKIA000",
"secret_access_key": "secret"
}
});
let p: AwsPollySpeakProvider = serde_json::from_value(raw.clone()).unwrap();
assert_eq!(p.voice, AwsPollyVoice::Joanna);
assert_eq!(p.engine, AwsPollyEngine::Neural);
assert_eq!(p.credentials.credentials_type, AwsCredentialsType::Iam);
assert_eq!(serde_json::to_value(&p).unwrap(), raw);
}
#[test]
fn long_form_engine_uses_kebab_case() {
let raw = json!({
"voice": "Brian",
"language": "en-GB",
"engine": "long-form",
"credentials": {
"type": "iam",
"region": "eu-west-1",
"access_key_id": "AKIA001",
"secret_access_key": "s"
}
});
let p: AwsPollySpeakProvider = serde_json::from_value(raw.clone()).unwrap();
assert_eq!(p.engine, AwsPollyEngine::LongForm);
assert_eq!(serde_json::to_value(&p).unwrap(), raw);
}
}