#![warn(clippy::all)] use serde::{Deserialize, Deserializer, Serialize}; use std::collections::HashMap; // Hermes protocol types #[derive(Debug, Deserialize)] struct HermesIntent { input: String, #[serde(rename = "rawInput")] input_raw: String, intent: HermesIntentClassification, #[serde(rename = "sessionId")] session_id: String, #[serde(rename = "siteId")] site_id: String, slots: Vec, } #[derive(Debug, Deserialize)] struct HermesIntentClassification { #[serde(rename = "confidenceScore")] confidence: f32, #[serde(rename = "intentName")] name: String, } #[derive(Debug, Deserialize)] struct HermesSlot { confidence: f32, entity: String, #[serde(rename = "slotName")] name: String, value: HermesSlotValue, #[serde(rename = "rawValue")] value_raw: String, } #[derive(Debug, Deserialize)] struct HermesSlotValue { value: String, } #[derive(Debug, Serialize)] struct HermesResponse { #[serde(rename = "sessionId")] session_id: String, text: Option, } #[derive(Debug)] pub struct Intent { pub name: String, pub input: String, pub input_raw: String, pub confidence: f32, pub session_id: String, pub site_id: String, pub slots: HashMap, } impl From for Intent { fn from(hermes_intent: HermesIntent) -> Self { let slots = hermes_intent .slots .into_iter() .map(|hermes_slot| (hermes_slot.name.clone(), Slot::from(hermes_slot))) .collect(); Self { name: hermes_intent.intent.name, input: hermes_intent.input, input_raw: hermes_intent.input_raw, confidence: hermes_intent.intent.confidence, session_id: hermes_intent.session_id, site_id: hermes_intent.site_id, slots, } } } #[derive(Debug)] pub struct Slot { pub confidence: f32, pub entity: String, pub value: String, pub value_raw: String, } impl From for Slot { fn from(slot_data: HermesSlot) -> Self { Self { confidence: slot_data.confidence, entity: slot_data.entity, value: slot_data.value.value, value_raw: slot_data.value_raw, } } } impl<'de> Deserialize<'de> for Intent { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let intent_data = HermesIntent::deserialize(deserializer)?; Ok(Intent::from(intent_data)) } } #[derive(Debug)] pub struct Response { pub session_id: String, pub text: Option, } impl Response { pub fn new(session_id: String) -> Self { let text = None; Self { session_id, text } } pub fn with_text(mut self, text: impl Into) -> Self { self.text = Some(text.into()); self } } impl From for Vec { fn from(response: Response) -> Vec { let hermes_response = HermesResponse::from(response); serde_json::to_vec(&hermes_response).unwrap() } } impl From for HermesResponse { fn from(response: Response) -> Self { HermesResponse { session_id: response.session_id, text: response.text, } } }