use serde_json::Value;
use tokio_stream::{Stream, StreamExt};
use regex::Regex;
pub struct InvokeParser {
buffer: String,
regex: Regex,
pub parsed_data: Vec<ParsedInvokeData>,
}
pub struct ParsedInvokeData {
pub tool: String,
pub action: String,
pub parameters: serde_json::Value,
}
impl InvokeParser {
pub fn new() -> Self {
InvokeParser {
buffer: String::new(),
regex: Regex::new(r#"<Invoke tool="(.*?)" action="(.*?)" parameters=(.*?)/>"#).unwrap(),
parsed_data: Vec::new(),
}
}
pub async fn parse_stream<S>(&mut self, mut stream: S)
where
S: Stream<Item = String> + Unpin,
{
while let Some(chunk) = stream.next().await {
self.buffer.push_str(&chunk);
while let Some(caps) = self.regex.captures(&self.buffer) {
let tool = caps.get(1).map_or("", |m| m.as_str());
let action = caps.get(2).map_or("", |m| m.as_str());
let params_str = caps.get(3).map_or("{}", |m| m.as_str());
let params: Value = serde_json::from_str(params_str)
.unwrap_or_else(|_| Value::Null);
let invoke_data = ParsedInvokeData {
tool: tool.to_string(),
action: action.to_string(),
parameters: params,
};
self.parsed_data.push(invoke_data);
let match_end = caps.get(0).unwrap().end();
self.buffer = self.buffer[match_end..].to_string();
}
}
}
pub fn parse(&mut self, msg: String) {
self.buffer.push_str(&msg);
while let Some(caps) = self.regex.captures(&self.buffer) {
let tool = caps.get(1).map_or("", |m| m.as_str()).to_string();
let action = caps.get(2).map_or("", |m| m.as_str()).to_string();
let params_str = caps.get(3).map_or("{}", |m| m.as_str());
let params: Value = serde_json::from_str(params_str)
.unwrap_or_else(|_| Value::Null);
let invoke_data = ParsedInvokeData {
tool,
action,
parameters: params,
};
self.parsed_data.push(invoke_data);
let match_end = caps.get(0).unwrap().end();
self.buffer = self.buffer[match_end..].to_string();
}
}
pub fn clear_buffer(&mut self) {
self.buffer.clear();
}
}
#[tokio::test]
async fn parses_nested_parameter_object() {
let input_stream = tokio_stream::iter(vec![
String::from("<Invoke tool=\"Translator\" action=\"translate\" parameters={\"text\": \"Hello\", \"options\": {\"from\": \"en\", \"to\": \"es\"}} />")
]);
let mut parser = InvokeParser::new();
parser.parse_stream(input_stream).await;
for data in &parser.parsed_data {
println!("Tool: {}, Action: {} Params: {}", data.tool, data.action, data.parameters);
}
assert_eq!(parser.parsed_data.len(), 1);
let invoke_data = &parser.parsed_data[0];
assert_eq!(invoke_data.tool, "Translator");
assert_eq!(invoke_data.action, "translate");
assert_eq!(invoke_data.parameters["text"].as_str(), Some("Hello"));
assert_eq!(invoke_data.parameters["options"]["from"].as_str(), Some("en"));
assert_eq!(invoke_data.parameters["options"]["to"].as_str(), Some("es"));
}