use std::str::Lines;
use reqwest::Response;
use serde_json::Value;
use crate::core::voiceflow::response_structures::voiceflow_response_block::VoiceflowResponseBlock;
use crate::core::voiceflow::response_structures::voiceflow_response_block_type::VoiceflowResponseBlockType;
use crate::core::voiceflow::VoiceflowMessage;
use crate::core::voiceflow::voiceflow_message::VoiceflowMessageBuilder;
use crate::errors::{VoiceflousionError, VoiceflousionResult};
#[derive(Debug)]
pub(crate) struct VoiceflowResponse {
response: Response,
}
impl VoiceflowResponse{
pub(crate) fn new(response: Response) -> Self {
Self { response }
}
async fn to_blocks(self) -> VoiceflousionResult<Vec<VoiceflowResponseBlock>> {
let text = self.response.text().await.map_err(|error| VoiceflousionError::VoiceflowResponseReadingError(error.to_string()))?;
let events = parse_sse(text.lines());
let mut blocks = Vec::new();
for data in events {
if let Ok(json) = serde_json::from_str::<Value>(&data) {
let response_type = get_response_type(&json);
match response_type {
VoiceflowResponseBlockType::Text
| VoiceflowResponseBlockType::Choice
| VoiceflowResponseBlockType::CardV2
| VoiceflowResponseBlockType::Visual
| VoiceflowResponseBlockType::Carousel
| VoiceflowResponseBlockType::End => {
let block = VoiceflowResponseBlock::new(response_type, json);
blocks.push(block);
},
_ => {}
}
}
}
Ok(blocks)
}
pub(crate) async fn to_message(self) -> VoiceflousionResult<VoiceflowMessage>{
let blocks = self.to_blocks().await?;
let message = VoiceflowMessageBuilder::new().build_message(blocks);
Ok(message)
}
}
fn parse_sse(lines: Lines) -> Vec<String> {
let mut events = Vec::new();
let mut current_data = String::new();
for line in lines {
if line.starts_with("data:") {
if !current_data.is_empty() {
current_data.push('\n');
}
current_data.push_str(&line[5..].trim());
} else if line.is_empty() {
if !current_data.is_empty() {
events.push(current_data.clone());
current_data.clear();
}
}
}
if !current_data.is_empty() {
events.push(current_data);
}
if events.len() >= 2 {
events = events[..(events.len() - 2)].to_vec();
}
events
}
fn get_response_type (json: &Value) -> VoiceflowResponseBlockType {
if let Some(payload_type) = json["trace"].get("type").and_then(|t| t.as_str()) {
return VoiceflowResponseBlockType::new(payload_type)
}
VoiceflowResponseBlockType::new("")
}