#![allow(clippy::all, unused_imports, dead_code)]
use crate::{Actor, ActorBehavior, ClientBuilderExt, Message, Port};
use anyhow::{Error, Result};
use reflow_actor::{message::EncodableValue, ActorContext};
use reflow_actor_macro::actor;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::time::Duration;
const BASE_URL: &str = "https://api.spoonacular.com";
const ENV_KEY: &str = "SPOONACULAR_API_KEY";
fn apply_auth(
config: &reflow_actor::ActorConfig,
mut builder: reqwest::RequestBuilder,
) -> Result<reqwest::RequestBuilder> {
let credential = config
.get_config_or_env(ENV_KEY)
.ok_or_else(|| anyhow::anyhow!("Missing env var: {}", ENV_KEY))?;
builder = builder.query(&[("apiKey", &credential)]);
Ok(builder)
}
#[actor(
SpoonacularSearchRecipesActor,
inports::<100>(query, cuisine, diet, intolerances, number, offset),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_recipes(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/complexSearch".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("cuisine") {
query_pairs.push(("cuisine", super::message_to_str(val)));
}
if let Some(val) = inputs.get("diet") {
query_pairs.push(("diet", super::message_to_str(val)));
}
if let Some(val) = inputs.get("intolerances") {
query_pairs.push(("intolerances", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if let Some(val) = inputs.get("offset") {
query_pairs.push(("offset", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/complexSearch failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipeInformationActor,
inports::<100>(id, includeNutrition),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe_information(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/information".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("includeNutrition") {
query_pairs.push(("includeNutrition", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/{{id}}/information failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipeActor,
inports::<100>(id, apiKey, includeNutrition, addWinePairing, addTasteData),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/information".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("includeNutrition") {
query_pairs.push(("includeNutrition", super::message_to_str(val)));
}
if let Some(val) = inputs.get("addWinePairing") {
query_pairs.push(("addWinePairing", super::message_to_str(val)));
}
if let Some(val) = inputs.get("addTasteData") {
query_pairs.push(("addTasteData", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/{{id}}/information failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListRecipesActor,
inports::<100>(apiKey, ids, includeNutrition),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_recipes(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/informationBulk".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("ids") {
query_pairs.push(("ids", super::message_to_str(val)));
}
if let Some(val) = inputs.get("includeNutrition") {
query_pairs.push(("includeNutrition", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/informationBulk failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListSimilarRecipesActor,
inports::<100>(id, apiKey, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_similar_recipes(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/similar".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/{{id}}/similar failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListRandomRecipesActor,
inports::<100>(apiKey, includeNutrition, include_tags, exclude_tags, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_random_recipes(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/random".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("includeNutrition") {
query_pairs.push(("includeNutrition", super::message_to_str(val)));
}
if let Some(val) = inputs.get("include_tags") {
query_pairs.push(("include-tags", super::message_to_str(val)));
}
if let Some(val) = inputs.get("exclude_tags") {
query_pairs.push(("exclude-tags", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/random failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipeTasteActor,
inports::<100>(id, apiKey, normalize),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe_taste(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/tasteWidget.json".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("normalize") {
query_pairs.push(("normalize", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /recipes/{{id}}/tasteWidget.json failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListRecipeEquipmentActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_recipe_equipment(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/equipmentWidget.json".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /recipes/{{id}}/equipmentWidget.json failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipePriceBreakdownActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe_price_breakdown(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/priceBreakdownWidget.json".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"GET /recipes/{{id}}/priceBreakdownWidget.json failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListRecipeIngredientsActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_recipe_ingredients(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/ingredientWidget.json".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /recipes/{{id}}/ingredientWidget.json failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipeNutritionActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe_nutrition(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/nutritionWidget.json".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /recipes/{{id}}/nutritionWidget.json failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListRecipeInstructionsActor,
inports::<100>(id, apiKey, stepBreakdown),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_recipe_instructions(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/analyzedInstructions".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("stepBreakdown") {
query_pairs.push(("stepBreakdown", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /recipes/{{id}}/analyzedInstructions failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeRecipeActor,
inports::<100>(apiKey, url, forceExtraction, analyze, includeNutrition, includeTaste),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_recipe(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/extract".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("url") {
query_pairs.push(("url", super::message_to_str(val)));
}
if let Some(val) = inputs.get("forceExtraction") {
query_pairs.push(("forceExtraction", super::message_to_str(val)));
}
if let Some(val) = inputs.get("analyze") {
query_pairs.push(("analyze", super::message_to_str(val)));
}
if let Some(val) = inputs.get("includeNutrition") {
query_pairs.push(("includeNutrition", super::message_to_str(val)));
}
if let Some(val) = inputs.get("includeTaste") {
query_pairs.push(("includeTaste", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /recipes/extract failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipeSummaryActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe_summary(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/summary".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/{{id}}/summary failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeRecipeInstructionsActor,
inports::<100>(apiKey, instructions),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_recipe_instructions(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/analyzeInstructions".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("instructions") {
body.insert("instructions".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /recipes/analyzeInstructions failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeCuisineActor,
inports::<100>(apiKey, title, ingredientList, language),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_cuisine(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/cuisine".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("title") {
body.insert("title".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("ingredientList") {
body.insert("ingredientList".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /recipes/cuisine failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeRecipeSearchQueryActor,
inports::<100>(apiKey, q, language),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_recipe_search_query(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/queries/analyze".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("q") {
query_pairs.push(("q", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/queries/analyze failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipeAutocompleteActor,
inports::<100>(apiKey, query, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe_autocomplete(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/autocomplete".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/autocomplete failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeRecipeNutritionEstimateActor,
inports::<100>(apiKey, title),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_recipe_nutrition_estimate(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/guessNutrition".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("title") {
query_pairs.push(("title", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/guessNutrition failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeFoodImageActor,
inports::<100>(apiKey, file),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_food_image(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/images/analyze".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("file") {
body.insert("file".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /food/images/analyze failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularSearchIngredientsActor,
inports::<100>(apiKey, query, addChildren, minProteinPercent, maxProteinPercent, minFatPercent, maxFatPercent, minCarbsPercent, maxCarbsPercent, metaInformation, intolerances, sort, sortDirection, offset, number, language),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_ingredients(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/ingredients/search".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("addChildren") {
query_pairs.push(("addChildren", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minProteinPercent") {
query_pairs.push(("minProteinPercent", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxProteinPercent") {
query_pairs.push(("maxProteinPercent", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minFatPercent") {
query_pairs.push(("minFatPercent", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxFatPercent") {
query_pairs.push(("maxFatPercent", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minCarbsPercent") {
query_pairs.push(("minCarbsPercent", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxCarbsPercent") {
query_pairs.push(("maxCarbsPercent", super::message_to_str(val)));
}
if let Some(val) = inputs.get("metaInformation") {
query_pairs.push(("metaInformation", super::message_to_str(val)));
}
if let Some(val) = inputs.get("intolerances") {
query_pairs.push(("intolerances", super::message_to_str(val)));
}
if let Some(val) = inputs.get("sort") {
query_pairs.push(("sort", super::message_to_str(val)));
}
if let Some(val) = inputs.get("sortDirection") {
query_pairs.push(("sortDirection", super::message_to_str(val)));
}
if let Some(val) = inputs.get("offset") {
query_pairs.push(("offset", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/ingredients/search failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadIngredientActor,
inports::<100>(id, apiKey, amount, unit),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_ingredient(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/food/ingredients/{id}/information".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("amount") {
query_pairs.push(("amount", super::message_to_str(val)));
}
if let Some(val) = inputs.get("unit") {
query_pairs.push(("unit", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /food/ingredients/{{id}}/information failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadIngredientAmountActor,
inports::<100>(id, apiKey, nutrient, target, unit),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_ingredient_amount(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/food/ingredients/{id}/amount".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("nutrient") {
query_pairs.push(("nutrient", super::message_to_str(val)));
}
if let Some(val) = inputs.get("target") {
query_pairs.push(("target", super::message_to_str(val)));
}
if let Some(val) = inputs.get("unit") {
query_pairs.push(("unit", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/ingredients/{{id}}/amount failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadIngredientConversionActor,
inports::<100>(apiKey, ingredientName, sourceAmount, sourceUnit, targetUnit),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_ingredient_conversion(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/convert".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("ingredientName") {
query_pairs.push(("ingredientName", super::message_to_str(val)));
}
if let Some(val) = inputs.get("sourceAmount") {
query_pairs.push(("sourceAmount", super::message_to_str(val)));
}
if let Some(val) = inputs.get("sourceUnit") {
query_pairs.push(("sourceUnit", super::message_to_str(val)));
}
if let Some(val) = inputs.get("targetUnit") {
query_pairs.push(("targetUnit", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/convert failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeIngredientsActor,
inports::<100>(apiKey, ingredientList, servings, language, includeNutrition),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_ingredients(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/parseIngredients".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("ingredientList") {
body.insert("ingredientList".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("servings") {
body.insert("servings".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("includeNutrition") {
body.insert("includeNutrition".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /recipes/parseIngredients failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadGlycemicLoadActor,
inports::<100>(apiKey, ingredients),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_glycemic_load(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/ingredients/glycemicLoad".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("ingredients") {
body.insert("ingredients".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /food/ingredients/glycemicLoad failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularSearchIngredientSubstitutesActor,
inports::<100>(apiKey, ingredientName),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_ingredient_substitutes(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/ingredients/substitutes".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("ingredientName") {
query_pairs.push(("ingredientName", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/ingredients/substitutes failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadIngredientAutocompleteActor,
inports::<100>(apiKey, query, number, metaInformation, intolerances, language),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_ingredient_autocomplete(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/ingredients/autocomplete".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if let Some(val) = inputs.get("metaInformation") {
query_pairs.push(("metaInformation", super::message_to_str(val)));
}
if let Some(val) = inputs.get("intolerances") {
query_pairs.push(("intolerances", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/ingredients/autocomplete failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularSearchGroceryProductsActor,
inports::<100>(apiKey, query, minCalories, maxCalories, minCarbs, maxCarbs, minProtein, maxProtein, minFat, maxFat, addProductInformation, offset, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_grocery_products(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/products/search".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minCalories") {
query_pairs.push(("minCalories", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxCalories") {
query_pairs.push(("maxCalories", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minCarbs") {
query_pairs.push(("minCarbs", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxCarbs") {
query_pairs.push(("maxCarbs", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minProtein") {
query_pairs.push(("minProtein", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxProtein") {
query_pairs.push(("maxProtein", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minFat") {
query_pairs.push(("minFat", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxFat") {
query_pairs.push(("maxFat", super::message_to_str(val)));
}
if let Some(val) = inputs.get("addProductInformation") {
query_pairs.push(("addProductInformation", super::message_to_str(val)));
}
if let Some(val) = inputs.get("offset") {
query_pairs.push(("offset", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/products/search failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadGroceryProductActor,
inports::<100>(upc, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_grocery_product(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/food/products/upc/{upc}".to_string();
if let Some(val) = inputs.get("upc") {
endpoint = endpoint.replace("{{upc}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/products/upc/{{upc}} failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListComparableProductsActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_comparable_products(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/food/products/comparable/{id}".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /food/products/comparable/{{id}} failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadProductAutocompleteActor,
inports::<100>(apiKey, query, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_product_autocomplete(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/products/suggest".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/products/suggest failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeGroceryProductActor,
inports::<100>(apiKey, title, upc, pureIngredient),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_grocery_product(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/products/classify".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("title") {
body.insert("title".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("upc") {
body.insert("upc".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("pureIngredient") {
body.insert("pureIngredient".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /food/products/classify failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeGroceryProductsActor,
inports::<100>(apiKey, products),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_grocery_products(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/products/classifyBatch".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("products") {
body.insert("products".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /food/products/classifyBatch failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularSearchMenuItemsActor,
inports::<100>(apiKey, query, minCalories, maxCalories, minCarbs, maxCarbs, minProtein, maxProtein, minFat, maxFat, addMenuItemInformation, offset, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_menu_items(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/menuItems/search".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minCalories") {
query_pairs.push(("minCalories", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxCalories") {
query_pairs.push(("maxCalories", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minCarbs") {
query_pairs.push(("minCarbs", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxCarbs") {
query_pairs.push(("maxCarbs", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minProtein") {
query_pairs.push(("minProtein", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxProtein") {
query_pairs.push(("maxProtein", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minFat") {
query_pairs.push(("minFat", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxFat") {
query_pairs.push(("maxFat", super::message_to_str(val)));
}
if let Some(val) = inputs.get("addMenuItemInformation") {
query_pairs.push(("addMenuItemInformation", super::message_to_str(val)));
}
if let Some(val) = inputs.get("offset") {
query_pairs.push(("offset", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/menuItems/search failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadMenuItemActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_menu_item(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/food/menuItems/{id}".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/menuItems/{{id}} failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadMenuItemAutocompleteActor,
inports::<100>(apiKey, query, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_menu_item_autocomplete(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/menuItems/suggest".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/menuItems/suggest failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadMealPlanWeekActor,
inports::<100>(username, start_date, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_meal_plan_week(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/week/{start-date}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("start_date") {
endpoint = endpoint.replace("{{start-date}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"GET /mealplanner/{{username}}/week/{{start-date}} failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadMealPlanDayActor,
inports::<100>(username, date, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_meal_plan_day(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/day/{date}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("date") {
endpoint = endpoint.replace("{{date}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /mealplanner/{{username}}/day/{{date}} failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularGenerateMealPlanActor,
inports::<100>(apiKey, timeFrame, targetCalories, diet, exclude),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_generate_meal_plan(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/mealplanner/generate".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("timeFrame") {
query_pairs.push(("timeFrame", super::message_to_str(val)));
}
if let Some(val) = inputs.get("targetCalories") {
query_pairs.push(("targetCalories", super::message_to_str(val)));
}
if let Some(val) = inputs.get("diet") {
query_pairs.push(("diet", super::message_to_str(val)));
}
if let Some(val) = inputs.get("exclude") {
query_pairs.push(("exclude", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /mealplanner/generate failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularCreateMealPlanItemActor,
inports::<100>(username, apiKey, hash, date, slot, position, type_, value),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_create_meal_plan_item(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/items".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("date") {
body.insert("date".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("slot") {
body.insert("slot".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("position") {
body.insert("position".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("type_") {
body.insert("type".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("value") {
body.insert("value".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("POST /mealplanner/{{username}}/items failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularDeleteMealPlanDayActor,
inports::<100>(username, date, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_delete_meal_plan_day(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/day/{date}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("date") {
endpoint = endpoint.replace("{{date}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.delete(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"DELETE /mealplanner/{{username}}/day/{{date}} failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularDeleteMealPlanItemActor,
inports::<100>(username, id, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_delete_meal_plan_item(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/items/{id}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.delete(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"DELETE /mealplanner/{{username}}/items/{{id}} failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadShoppingListActor,
inports::<100>(username, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_shopping_list(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/shopping-list".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /mealplanner/{{username}}/shopping-list failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularCreateShoppingListItemActor,
inports::<100>(username, apiKey, hash, item, aisle, parse),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_create_shopping_list_item(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/shopping-list/items".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("item") {
body.insert("item".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("aisle") {
body.insert("aisle".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("parse") {
body.insert("parse".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"POST /mealplanner/{{username}}/shopping-list/items failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularDeleteShoppingListItemActor,
inports::<100>(username, id, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_delete_shopping_list_item(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/shopping-list/items/{id}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.delete(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"DELETE /mealplanner/{{username}}/shopping-list/items/{{id}} failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularGenerateShoppingListActor,
inports::<100>(username, start_date, end_date, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_generate_shopping_list(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/shopping-list/{start-date}/{end-date}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("start_date") {
endpoint = endpoint.replace("{{start-date}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("end_date") {
endpoint = endpoint.replace("{{end-date}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert("error".to_string(), Message::Error(format!("POST /mealplanner/{{username}}/shopping-list/{{start-date}}/{{end-date}} failed: {}", e).into()));
}
}
Ok(output)
}
#[actor(
SpoonacularCreateUserActor,
inports::<100>(apiKey, username, firstName, lastName, email),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_create_user(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/users/connect".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /users/connect failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadWinePairingActor,
inports::<100>(apiKey, food, maxPrice),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_wine_pairing(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/wine/pairing".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("food") {
query_pairs.push(("food", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxPrice") {
query_pairs.push(("maxPrice", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/wine/pairing failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadDishPairingActor,
inports::<100>(apiKey, wine),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_dish_pairing(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/wine/dishes".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("wine") {
query_pairs.push(("wine", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/wine/dishes failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadWineDescriptionActor,
inports::<100>(apiKey, wine),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_wine_description(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/wine/description".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("wine") {
query_pairs.push(("wine", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/wine/description failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListWineRecommendationsActor,
inports::<100>(apiKey, wine, maxPrice, minRating, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_wine_recommendations(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/wine/recommendation".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("wine") {
query_pairs.push(("wine", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxPrice") {
query_pairs.push(("maxPrice", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minRating") {
query_pairs.push(("minRating", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/wine/recommendation failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularSearchFoodActor,
inports::<100>(apiKey, query, type_, cuisine, diet, intolerances, offset, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_food(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/search".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("type_") {
query_pairs.push(("type", super::message_to_str(val)));
}
if let Some(val) = inputs.get("cuisine") {
query_pairs.push(("cuisine", super::message_to_str(val)));
}
if let Some(val) = inputs.get("diet") {
query_pairs.push(("diet", super::message_to_str(val)));
}
if let Some(val) = inputs.get("intolerances") {
query_pairs.push(("intolerances", super::message_to_str(val)));
}
if let Some(val) = inputs.get("offset") {
query_pairs.push(("offset", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/search failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularSearchFoodVideosActor,
inports::<100>(apiKey, query, type_, cuisine, diet, includeIngredients, excludeIngredients, minLength, maxLength, offset, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_food_videos(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/videos/search".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("type_") {
query_pairs.push(("type", super::message_to_str(val)));
}
if let Some(val) = inputs.get("cuisine") {
query_pairs.push(("cuisine", super::message_to_str(val)));
}
if let Some(val) = inputs.get("diet") {
query_pairs.push(("diet", super::message_to_str(val)));
}
if let Some(val) = inputs.get("includeIngredients") {
query_pairs.push(("includeIngredients", super::message_to_str(val)));
}
if let Some(val) = inputs.get("excludeIngredients") {
query_pairs.push(("excludeIngredients", super::message_to_str(val)));
}
if let Some(val) = inputs.get("minLength") {
query_pairs.push(("minLength", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxLength") {
query_pairs.push(("maxLength", super::message_to_str(val)));
}
if let Some(val) = inputs.get("offset") {
query_pairs.push(("offset", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/videos/search failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadQuickAnswerActor,
inports::<100>(apiKey, q),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_quick_answer(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/quickAnswer".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("q") {
query_pairs.push(("q", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/quickAnswer failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularAnalyzeFoodTextActor,
inports::<100>(apiKey, text),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_analyze_food_text(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/detect".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("text") {
body.insert("text".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /food/detect failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularSearchSiteContentActor,
inports::<100>(apiKey, query),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_search_site_content(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/site/search".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/site/search failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRandomFoodJokeActor,
inports::<100>(apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_random_food_joke(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/jokes/random".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/jokes/random failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRandomFoodTriviaActor,
inports::<100>(apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_random_food_trivia(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/trivia/random".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/trivia/random failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadChatbotActor,
inports::<100>(apiKey, text, contextId),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_chatbot(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/converse".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("text") {
query_pairs.push(("text", super::message_to_str(val)));
}
if let Some(val) = inputs.get("contextId") {
query_pairs.push(("contextId", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/converse failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListChatbotSuggestionsActor,
inports::<100>(apiKey, query, number),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_chatbot_suggestions(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/food/converse/suggest".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("number") {
query_pairs.push(("number", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /food/converse/suggest failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularCreateRecipeCardActor,
inports::<100>(apiKey, title, ingredients, instructions, readyInMinutes, servings, mask, backgroundImage, author, backgroundColor, fontColor, source),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_create_recipe_card(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/recipes/visualizeRecipe".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("title") {
body.insert("title".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("ingredients") {
body.insert("ingredients".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("instructions") {
body.insert("instructions".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("readyInMinutes") {
body.insert("readyInMinutes".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("servings") {
body.insert("servings".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("mask") {
body.insert("mask".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("backgroundImage") {
body.insert("backgroundImage".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("author") {
body.insert("author".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("backgroundColor") {
body.insert("backgroundColor".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("fontColor") {
body.insert("fontColor".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("source") {
body.insert("source".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /recipes/visualizeRecipe failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadRecipeCardActor,
inports::<100>(id, apiKey),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_recipe_card(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/recipes/{id}/card".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /recipes/{{id}}/card failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
SpoonacularListMealPlanTemplatesActor,
inports::<100>(username, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_list_meal_plan_templates(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/templates".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("GET /mealplanner/{{username}}/templates failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularReadMealPlanTemplateActor,
inports::<100>(username, id, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_read_meal_plan_template(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/templates/{id}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"GET /mealplanner/{{username}}/templates/{{id}} failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularCreateMealPlanTemplateActor,
inports::<100>(username, apiKey, hash, name),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_create_meal_plan_template(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/templates".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("name") {
body.insert("name".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!("POST /mealplanner/{{username}}/templates failed: {}", e).into(),
),
);
}
}
Ok(output)
}
#[actor(
SpoonacularDeleteMealPlanTemplateActor,
inports::<100>(username, id, apiKey, hash),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn spoonacular_delete_meal_plan_template(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mealplanner/{username}/templates/{id}".to_string();
if let Some(val) = inputs.get("username") {
endpoint = endpoint.replace("{{username}}", &super::message_to_str(val));
}
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.delete(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("apiKey") {
query_pairs.push(("apiKey", super::message_to_str(val)));
}
if let Some(val) = inputs.get("hash") {
query_pairs.push(("hash", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"DELETE /mealplanner/{{username}}/templates/{{id}} failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}